From d180610fc45e046b5a2e5d41d65c029acdb3482a Mon Sep 17 00:00:00 2001
From: "lucas.toniutti" <lucas.toniutti@etu.hesge.ch>
Date: Thu, 29 Jun 2023 01:16:11 +0200
Subject: [PATCH] Ajout d'un nouveau indicateur + importation/exporation des
 simulations

---
 main/.DS_Store                              | Bin 8196 -> 8196 bytes
 main/Decision.py                            | 147 ++++++--
 main/__pycache__/Decision.cpython-310.pyc   | Bin 6583 -> 8087 bytes
 main/__pycache__/settings.cpython-310.pyc   | Bin 263 -> 163 bytes
 main/__pycache__/simulation.cpython-310.pyc | Bin 13384 -> 13418 bytes
 main/backend.py                             | 388 +++++++++++++++++---
 main/settings.py                            |   3 -
 main/simulation.py                          |  18 +-
 main/static/.DS_Store                       | Bin 6148 -> 6148 bytes
 main/templates/base.html                    |   8 +-
 main/templates/importSimulation.html        | 154 ++++++++
 main/templates/index.html                   | 147 +++++---
 main/templates/mySimulation.html            | 138 +++++++
 13 files changed, 848 insertions(+), 155 deletions(-)
 delete mode 100644 main/settings.py
 create mode 100644 main/templates/importSimulation.html
 create mode 100644 main/templates/mySimulation.html

diff --git a/main/.DS_Store b/main/.DS_Store
index 6b5e74f656eba8670e3dd860975b345bb0c5faef..36bd23a29fd01e459ee9050142a5b5a30ac952f2 100644
GIT binary patch
delta 125
zcmZp1XmOa}&nUAoU^hRb%w!&ciIdBOOF4`zEp!x&4NWJ17Pg<<Bq+W)U$B#rpPQkW
zA(f$op@bomA&((_@<kzW)@}v{hIy0U3jKrY+5A~}1tWsDSX7s3GrPn$mdVFNt|AL-
GF#!MpaU@g#

delta 152
zcmZp1XmOa}&nUeyU^hRb^kg1^iHzGP&l4zA6R)l|vCvU4GP9`FQK+^wGSE>lF*d8M
z<>U}m*0&Cd&(6us%kP|QCMeI?HMv1hYIA{LC*x#&;m;h#CMG%xMy3{<wM14hau^$#
o>nIpmm~Fl#s>?L7!F)5j#5Wd>|6sttFnNNQ*yJG526Sa60I=CF#sB~S

diff --git a/main/Decision.py b/main/Decision.py
index 7ebc93d..4ce5faa 100644
--- a/main/Decision.py
+++ b/main/Decision.py
@@ -14,7 +14,6 @@ import os
 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
 sys.path.append(os.path.dirname(SCRIPT_DIR))
 
-import settings
 import asyncio
 import websockets
 from orders import TradesManagement
@@ -59,8 +58,11 @@ class Decision:
         self.amount = None
         self.export_result = []
         self.mas = []
-    #Launch a simualtion for a given market ==> focused on MA
-    def simulationGen(self,sim,symbol,sizeCandle_min,mas):
+        self.timeRandom = []
+        self.tmpRandom = 0
+        self.tickRandom = 0
+    #Launch a simualtion for a given market
+    def simulationGen(self,sim,symbol,sizeCandle_min,indicator,mas=[],timeRandom=[]):
         cpt = 0
         self.sim = sim
         random.seed(dt.now())
@@ -78,29 +80,52 @@ class Decision:
         print(f"time period = {self.timePeriod}")
         self.sim.indexTicker +=1
         
-        #Iterate on each price of a market        
-        for i in range(1,len(sim.histo_prices)):
-            self.sim.indexTicker +=1
-            self.indexTickerSim+=1
-            try:
-                price = self.sim.histo_prices[self.indexTickerSim][0]
-                date = self.sim.histo_prices[self.indexTickerSim][1]
-            except:
-                print("Erreur dans la simulation dans le calcul du SMA.")
-                print(f"Liste len : {len(self.sim.histo_prices)}")
-                print(f"Index : {self.indexTickerSim}")
-                break
+        if indicator == "SMA":
+            #Iterate on each price of a market for SMA calculation
+            for i in range(1,len(sim.histo_prices)):
+                self.sim.indexTicker +=1
+                self.indexTickerSim+=1
+                try:
+                    price = self.sim.histo_prices[self.indexTickerSim][0]
+                    date = self.sim.histo_prices[self.indexTickerSim][1]
+                except:
+                    print("Erreur dans la simulation dans le calcul du SMA.")
+                    print(f"Liste len : {len(self.sim.histo_prices)}")
+                    print(f"Index : {self.indexTickerSim}")
+                    break
 
-            self.pricesSim.append([price,date])
-            #Launch SMA calculation
+                self.pricesSim.append([price,date])
+                #Launch SMA calculation
 
-            # Mettre les décisions
-            self.calculateSMA(date,symbol,price,mas)
-            if self.indexTickerSim >= len(sim.histo_prices)-1:
-                break
-        print(f"date End = {date}")
-        #add results to list of results
-        self.export_result.append(sim.endSimulation(mas)) 
+                # Mettre les décisions
+                self.calculateSMA(date,symbol,price,mas)
+                if self.indexTickerSim >= len(sim.histo_prices)-1:
+                    break
+            print(f"date End = {date}")
+            #add results to list of results
+            self.export_result.append(sim.endSimulation(mas)) 
+        if indicator == "random":
+            #Iterate on each price of a market for random decision
+            for i in range(1,len(sim.histo_prices)):
+                self.sim.indexTicker +=1
+                self.indexTickerSim +=1
+                try:
+                    price = self.sim.histo_prices[self.indexTickerSim][0]
+                    date = self.sim.histo_prices[self.indexTickerSim][1]
+                except:
+                    print("Erreur dans la simulation dans le calcul du random.")
+                    print(f"Liste len : {len(self.sim.histo_prices)}")
+                    print(f"Index : {self.indexTickerSim}")
+                    break
+                self.pricesSim.append([price,date])
+                
+                self.calculateRandom(date,symbol,price,timeRandom)
+                if self.indexTickerSim >= len(sim.histo_prices)-1:
+                    break
+            print(f"date End = {date}")
+            self.export_result.append(sim.endSimulation(timeRandom))
+        else:
+            print("Error in the indicator choice")
 
     #Detection of  the crossing of a mooving average
     def detectCrossMA(self,short_ma,long_ma,price,date):
@@ -114,14 +139,17 @@ class Decision:
                 self.crossed = "down"
 
     #Launch our decision algorithme for a simulated or realtime
-    def launch(self,dateStart, dateEnd, show_graph = True, SL = 0.03, TP = 0.03, candle_size = 10, mas=[20,40]):
+    def launch(self,dateStart, dateEnd, indicator, show_graph = True, SL = 0.03, TP = 0.03, candle_size = 10 ,mas=[20,40], timeRandom=[15,20]):
         testSL = [float(SL)]
         testTP = [float(TP)]
         candle_sizes = [int(candle_size)]
         
         # Moyenne glissante
         # mas = [[10,20],[5,15]]
-        self.mas = [mas]
+        if indicator == "SMA":
+            self.mas = [mas]
+        if indicator == "random":
+            self.timeRandom = [timeRandom]
         
         markets = ["BTCUSDT"]
         bases= ["BTC"]
@@ -147,19 +175,29 @@ class Decision:
                 #amout is 10% of balance
                 self.amount = balance*0.1
                 
-                for sl in testSL:
-                    self.sim.sl = sl
-                    for tp in testTP:
-                        self.sim.tp = tp
-                        for c in candle_sizes:
-                            for ma in self.mas:
-                                print(f"Simulation of market : {market} with sl = {sl} and tp = {tp} and candle_size = {c} and ma = {ma}")
-                                print("Amount = ",self.amount)
-                                print(self.sim)
-                                self.simulationGen(self.sim,market,c,ma)
-                                # self.sim.resetSimul(sl, tp, market,bases[i], targets[i])
-                                # self.resetLists(market)
-            # plot_MA_Price_Orders(self.sma['BTCUSDT'],self.sim.histo_prices,[20,40],self.sim.active_orders,"BTCUSDT")
+                if indicator == "SMA":
+                    for sl in testSL:
+                        self.sim.sl = sl
+                        for tp in testTP:
+                            self.sim.tp = tp
+                            for c in candle_sizes:
+                                for ma in self.mas:
+                                    print(f"Simulation of market : {market} with sl = {sl} and tp = {tp} and candle_size = {c} and ma = {ma}")
+                                    print("Amount = ",self.amount)
+                                    print(self.sim)
+                                    self.simulationGen(self.sim,market,c,indicator,mas=ma)
+                if indicator == "random":
+                    for sl in testSL:
+                        self.sim.sl = sl
+                        for tp in testTP:
+                            self.sim.tp = tp
+                            for c in candle_sizes:
+                                for timeRand in self.timeRandom:
+                                    print(f"Simulation of market : {market} with sl = {sl} and tp = {tp} and candle_size = {c} and random time = {timeRand}")
+                                    print("Amount = ",self.amount)
+                                    print(self.sim)
+                                    self.simulationGen(self.sim,market,c,indicator,timeRandom=timeRand)
+
             export_Simulation_All(self.export_result)
             
             
@@ -188,6 +226,10 @@ class Decision:
         self.amount = None
         self.export_result = []
         self.mas = []
+        self.timeRandom = []
+        self.tmpRandom = 0
+        self.tickRandom = 0
+        
     #Format string to datetime
     def formatDateStr(self,datestr,format):
         return datetime.strptime(datestr,format)
@@ -294,4 +336,29 @@ class Decision:
                 self.detectCrossMA(ma1,ma2,price,date)
             return 1
         return 0
-        #print(self.sma)
\ No newline at end of file
+        #print(self.sma)
+    
+    #Choose a random time to buy or sell
+    def calculateRandom(self, date, symbol, price, timeRandom):
+        if self.init:
+            self.init = False
+            self.randomAVorVA(date,price)
+            return 1
+        if not self.init:
+            # 1 tick = 10s
+            if self.sim.end_Active < self.sim.indexTicker and self.tmpRandom == 0:
+                self.tmpRandom = 1
+                rand = random.randint(timeRandom[0],timeRandom[1])
+                rand = (rand*60)/10
+                self.tickRandom = self.sim.indexTicker + rand
+            if self.sim.indexTicker == self.tickRandom:
+                self.tmpRandom = 0
+                self.randomAVorVA(date,price)
+        return 1
+
+    def randomAVorVA(self, date,price):
+        rand = random.randint(0,1)
+        if rand == 0:
+            self.sim.placeOrder(price,self.amount,date,"AV","GTC")
+        elif rand == 1:
+            self.sim.placeOrder(price,self.amount,date,"VA","GTC")
\ No newline at end of file
diff --git a/main/__pycache__/Decision.cpython-310.pyc b/main/__pycache__/Decision.cpython-310.pyc
index 31410ac5b63ed1dafc47bab0ccf17b90fc033e4f..588d4e35b656af4aa8b0f4a4dc1a0ff0f28b0a07 100644
GIT binary patch
delta 3691
zcmdmPJl&ozpO=@5fq{Wxn%$g~2No0gWEj6q)b^`q%Hhi8j^buyNMT4}&f&@Bjp7Bf
zS#tPt`J?#3Y{ndcD8Uql6viB(C?PN{93`B>kiwcHk}DD=0#zd#B?=c41B<cci04W~
zN#sgKN#;sLNrA=KbEI=+qGWPqqhvvRjTFWlxhQ$Cp$buoU|K0xIZB0*!JQ$6BZaet
zA%(M<DN1#+2ICe@b_NCp2L=X);wA<LhE#?q#uSDqrWD2$rWS@M=5&U1hBT%W<`k9|
z#>xK~B?3}-Qn=EY(%4dXQ}|jKqu5gTQv_NVqS#XeQ-oR=qBv6IQ$$ikTNtA_Q^Zol
zTNt9aQY2C&TNt9aQ>0R)TNt8vQe;wOTNt8vQ{;jfG!-TXGN~}mnOw%yDU{Ao!w@f=
z!dk-+F9Ie-C;w-%VicQf#k|Mz7FS7TZfa0sUP^xMEzXkM0w|NKBr`c1!q#NI#ZsJ_
zlUBsfz`#%>$H2g_lA%a#G7n2AuL{V2It&a9Y)k@7lO6aKnAjL6cd<y-gFFw4KoI6*
zU|`^2U|?_tDc-@vz>vaN%U;7+!w}C<!nlB`gn0qWLWYHmj39B266OW0HH=woDU6Z~
zDNK?KDa;F*YB}MeAQ2D-iE`C&)o@BMEMQ;AP|IDyk-}2LIh$cFQ!^tYgIWnk3Tq7)
zj9bEy!dAl#=W*6Br?87K)NoJsWYyrPVM*c4W-7WexsX+uk!Nx%tDz=u4MP?~7F!KN
z79YeFwH)CLd9sWQAXvhY!UeLUgd>G}@_km(dLEEEnBkEOj0}ZGY8bNk7YNkw)^MaV
zfqYiOut2beqlT%5w}y2g3nK$aM+q;;pUsRZOcD&)tVM@G`U+D@I8u0PIAEsLFk}fW
z5U62XAY8+`kP&PWOA22$(*(w%uo9jWCXg9CS!~UW%}g!~u}QV~oG%A*JR?I1M+!fF
z=TBfPbiv{Q5vT{)uzO$vW05l>14wV-L!6#qgLoo^AsFNi0gyY`KpaiM$?0sFthbnh
zeH|xXU<>EE#a0APl2yi&FR|$uK{$F<vaUr%`9%tuc?u;NsS25SDVfQMCHX}P$r<^X
z$*G#6MPi^N3QCZZ&Dh-;Z%wXa_Yu9tpPZPJT$+<u0!`<dd_}60&#}u2-Qt8BQKSgc
zsWka5yS}m-hzTat85kID@fK(1f^=u*=eeimIf7Dg#$<aASr!f^5vIv;915C3Ok9j2
zOahF2j7*F|jAD#zj2w(&i~@`ti~@`TOdvkfe?BHLMxM#_9GeVoF}sI2-(pG0FVDNh
z6y~VOQX~$t5aje*Tm?Ca$*KNDDXB$8@(c_Nnrua?lM^|`^+47Z*@B$Il2w{pPy}`!
zn1Hx3CAB0qxx~3Bzqr`fv3c?`PXGFsp!}K)E=NJxkb!|gl7WFi0G1QYm>3vJ7;0FX
z8PgeSxk?yn*uX6A62=;KFpH;#IfXHssYtwrBOR1mnQE9*n6jCQ<ZC#=eC8D9bjDiV
z6qa<xTD}z4bjDi#8ip*E6t--pBF7Te`V@9h{Fbn#aHMcFGt~;z2!OIGBSVeA0*-|Y
zj0~I%oD7BbU@ctWBrRFOn!*j%!<oX6!cfDT!XwF0!v`k$L1Z(i4C5-{uHkKFbYY0y
z9K%#ASSwV+kj1rtCxy30sD`D6v4&|OD>#GIb1mSl;j0mpWLU^pD_kQ~!w}C`Bb>q~
z0xAyqp?*77!{x#d>s%{RBLXreUZ95Cg(23eR<uSG%onWTabbuxtQD(a$O2_C?OO2?
z))f94q1g;60yQGD8BzpmL}xRk2-S$qW=IjP5ueR47g9Q~)~A4s<ZotTWGG<;83yth
zC_{tTH9|FFHOw{QDWbisj0}a-3nvwJ6*fTvcmiXQAPLT5c43Isu9d)WRu;ltVl@&7
zcM;(%i4<|LvmO=RExcNIwlJ<lxP~E11mpowZUtdY3BMw3P_hMQwh7#O92vn`s7hEN
zF)u{{l3^7<b&G<nf+k~;5-2f?-eOJ5$xkdPG6Cs?<Twxulu(O|C#Uih>N$b<pfp>g
z0Ma2@q{_g+5XG62SdtoCl2}v{#SUV+=A{%_GcYhr{?DVvRHQUniPxnbRM*~O%S|lG
zPA$2`o|KrAn3tSd6a+Fa7?f`qlW#HQCPs09+ytuF(6bO*PGV_Zaz-C0e-|+@FmN$~
zAO{NvBM7oFu`#kSaxrl*a)J3wj7&^S|9F@=nB*7*m_!%_CST>{Hv!42G4e2SF-kBp
z{bBmg^pA@Jq#J^{7*XYz8u&O_?oR&2tIarVvKn8rEV!l?0@u;7`kEn_p@;_*5~7p0
z@I~2x!?8#i<S9_ytH}foA8@6N?jNqA)Z)|<pUmQt;<F$>X-&4~R|VD2G5i761|TDu
z!J2P@L$tW0=oVXAeo<~>3A#bN5MdW^6coMM{G8vGkui0$s-O|0>f{JPc{WhRUgS2p
zR!~wFTq1!9aIwULD0zcD-)-J3_??kk6XbYMo1jQ*@>XFJQ*#hs6hv5n2qO?70wQEV
z1URMSfLLB2C-Z`xT$DFiPDDZ!R3_eHF3Bw@0>yn1sAMaOo9r!OC=GT2m;gJ2Go>^)
zw=zE1*O8fV^K_A~jNFAF6Qw|e#pLN?TJ<1D++r@sFDL?A!vnDfRNg|u7GzZvXF+OF
zW`0V1ZemdhNUIHq09k#Dslf0SQ-RSf=G;U>5MhKChDDYP3=BGq3=G9~;KmXQ6AL&M
z@iFo+@-gx;PIeG?u1{u#7SkY#je&sy#0Q0K@e~FIP?Le7h%W_H5Hr*;EMTl*tYKcr
z#K@4s6bzOt_5c-8S<GOPC7YqhqJ|-hHHA5wsmLOQsfHn*wS;W}dksqpvm`?e3#e(e
zkg1lnhBbvngdv4hnxVEHR7f#pvDC1NgGxvah(R?BSsd9+MII^4AS2K%)@1W@D+0$Q
zBPcAiK!i6ao;ZtyL3xe`QVuwV<rjrHf-C1JuGGAgc*o?D%(B!XQ;>RaV%A|`sAssv
z4pN?(S5gE{+ich(0h|GDv49k!hp`m{149@njAcM!%*e*b!^pzO#wf+a#wY>}XNXvp
zgiC62W^rbIo*p87Cf0+Rz{$*@z=vWM1_lODLlztdAq=4EaseZ#1;3D~mKj=sh=YP@
z0dox#s2;0f1hwcv^$)0sgp}q*8fYq5Q&?asK&mv^{EEPVR}T(H7f_J6f(Um|II<Rj
z%GaV=kN~KGP~-t($%CX=kb(!4Jd5f;Qs6`nCO|2_sD^=oAsrMZpfZGqk%LhRj9LCy
ziNeDG6qfn9jsoCF^3!B0N?>4M2+`!5+$XMDuK_X?TquJwMo~0~8v`QZK}0@?C<76o
z1YQJ+0kD-wQG;*`Hv<C$D6)$sz#Re(Mm|{%Cpm5odk$GH77kGkO%5#{!6J|<O|@Ih
z#g)aknDQs9NEony%7w{E5-9?uAe%tB0um~EldnmHF&0hMm9#JbTZ14#p1;LmlbfGX
cnv-e=3g2Q-;^g4sU=(2zVdP+%JY7-&01+7;T>t<8

delta 2319
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
HTwVbHBIfU9

diff --git a/main/__pycache__/settings.cpython-310.pyc b/main/__pycache__/settings.cpython-310.pyc
index 65766bb99a0b8558a53a733e3133f29d579d0426..a58aa08ba9ef7cf1551657b2ad446cc9e41e96f2 100644
GIT binary patch
delta 142
zcmZo?TFmH?&&$ijz`($;)qipdh<*$rkTD|z1A_wt14A(j0|P?}LokCTqu)w~B9JhG
z_~kaSUCy>RGq*G+u_U#$sH7+{B{MHQxu~+BBws%_F*8rUIJKlCGcUbZub}c4hfQvN
SN@-529mteoCI$uu76t%w>mWY>

literal 263
zcmd1j<>g{vU|`tiSe9bOz`*br#6iYP3=9ko3=9m#JPZsBDGVu$Eeuf%DNMl(n#{?_
z>OgEp1_lOakXjCqTE;|%6oz01O(wsWAW2QeTigXj`RPTe#l=pEMJpMKm>C!##4k(z
z(BjmhV*Q-b<iuiqm(=3ylKcXFr^Mup)SUbx{ltQTlA^?v%)E5{+{Da0{o>S;lFYpH
zV!eXOTP&G*nI#~Li$N~sU@Br|U|{gmWCYU)D<CWu1_p*(95%W6DWy57c5q!h3;?>D
BGpGOn

diff --git a/main/__pycache__/simulation.cpython-310.pyc b/main/__pycache__/simulation.cpython-310.pyc
index e6f8c914f44e21d1aee9d3a287b06ef1cb1f8865..8369cbfc9bebda0632912157ca577bca7636a32c 100644
GIT binary patch
delta 2843
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
K9uQ^}Vg>+Hgq33e

delta 2838
zcmaEraUz2+pO=@5fq{YH;itxw=CFx;GK?V;wO`h!Fr+Z%C`Ku!DrPAyPzIAKsj3SZ
z7cxevr7C18El>xGDW|G|#26V;7*e=$G;%egG{J1{9IagKDD7OGD4ks0C|$4^PmW%$
zew02VgF8bCZwg-vLkeFrQ<OmpV=#jz|4Wb?{4^PFu?1J=CgpGLX1vJAxN34N^D0(`
zU<OU@$r3DyOq!CLYghysC$D5xVl<w7hBcf`hk=2i*l4mQoAKrZwlGE=0|o|$Tg*kN
z#kUv>ii{Z;7$AfRNSLoEH7&m=H?bt3C^I>=*kke|_G^p=lXr5cN~5Xdf~a#zEJ+QU
z{F5V23T!M#a%oXfYF=_B#7wXrlgWjg5{z+^yEyMCx`HfWFHTM@DM>9VasgS+0TN<K
z&QDF#<SH_l+|Fe$3DyQCz>eZ5$jL8pE6qzzntY$jk#XK+MecdRARn{%6^Vk3U}Rum
zaMP5We4ksB%@8DDG?|ab%iIrSGIL&jd676sP#;8qO$8HRqq&Mwi&IO2GjmIGvcSQ_
zz`!thA&=VR05%RruE}S3ma&v@WpPg~<5hO&sS!zGUC2}`TEm>emd#X@Qp2!-w?<?k
zW35OD-va&`ffPnbhJ}o^0yP3D?2-(%VtK+P0wsbF@n*(mMn(pZy2%fCMKyV9*uZ9q
zmoP2hsbL4RC2AyU#3dLO2rXo&m8=nkuqVs$iCL9!#dDW1Ef5A-RwA-MG=;H-X(5vY
zL#;>+cM4-RQ_&%al{GvmoHh(4Vl^Voj5RzdTs91o7x0NqZsFU_C^p%F-=9%@@&tZu
zM)Ape_|@wrYJ_Tpo0)1AN+fF(vZPW#$y2D6S(2fdu~xB0u|#@-ObypU#%9J^r4rd1
zrDjGKhFJa>rdr-w<r29X*%J90nHuG0re>xZr5auvh6#*?oi$1>46!1$$~7WTS28YS
z5(l}GV*y)@GQ?eJObZzq8745Q6wWTRsbNiF&SsjxShTx_VSz#o2S}=hvxXsFv4*3D
zAzo>6n}BnDFen;XJTlWWiZVb<W}p1>qD%$`hL=pB7&QZlu_ou_7pE4*F)%P_D&Jx&
zO3X{i&%MP`oSK?a1WE=)xnNaAiFxU%x0o~YN{Z}3dO^9mhzG=y1j%z0r<Rmt=A{?k
z;w~u4PcKR>E_O;3FDmi}sR#!V4j{r2MA%LC6%1fY0x{z!FBUXsG?;u_&`->Rfq@~4
zvnaLLIWaFKC$%UIq#$duy^sla3W%8sB7!H^359!rJOlPe6xhA-hEUq5C>i7!mbB8m
z<f3$tdQT7mPPAYGoN_sm6LXUNoqasoC(8;eGBQrK7glCu+MF!R#mE>uIZwn(9OOey
z_99TeESd~5VG4){o_t<J$`EW0m;f8bRgjaIoa$ecl3Mf^lnwY87#Mh%*q9_3c^JhQ
z*;v_FCQFGnFxpL?EvldlHgGz~tO+0jYzmkF8C5imfq_AA@;%WQwFsE(N@gTSsKG=b
zC4|Z31TiT_>B-e%;Zkr7MRU;=y%CdPl$*>cUdU)LxmsLV6>J}v09krVBsn8BIomTW
zxFo+Iv>+%oF*zeOMRD?B@p5&rA}|3~DTbudCBHlms#bk+qQqPQbC9(bAi@$vSWo7Y
zlniwOF`Yp%!d;RdpORRTT9TQY3Msol#aWRXNP#qna0ewnWY2<91H_+j7ZkNKFfiy%
zu8~~HW(P7<Wby}95hX+-Ez$;w@}^c4<QJ6$r52awloV^S78y)Vlv0-in*t`lp5aZ+
zO97W%i6xo&dFGp!Nr^DAlnBHNZr&$j!pJBz`LnDVqupdFIawJ<u?TWx4v44*5j7y^
z@)a3O_LGa1#OBmh3=9nRlaI)?GBR%VlJ{nn1-qCfJGHX7hy`TAZV&-7P*b$XVDcuF
z$s%CKfeDZci&io)Fyu{+R6V5+k6cYi0Nr9POUx-kPYodR4lpn<9M~MBwvCY=l=X`Q
zL4s33`D(JbhQ5OlD17*GGxJJIQj48ZOUhGI^NQp_YCs9TXc>qF_N@YlrOd#<u#yd&
z{%$en7o`+sO>WcBM0e(F1_p*BlMid$U<{r-N7E3J#Lt2BgK7oz7(C6u!0=}C2hF35
zp&(`vI20s6s==0n99VP)#8m_lU{@^xvB0iU0<l1@Dmn{dfrAQ6fWvDJ0|Udi$y_>{
zqJ0<`7%~O;7#NB`wcAP-ND2X$M0KDLU`xp?%gs*#B@GalDaG&>Q;N|o_LBUP_~O*$
zTdW!RrA5W)PQS>&z@Ri)T-P<^5-9Rn{E9&K6h(ua0<x#*GDw&e99~6NL88|{#C4Dr
z?9ebrHxuMlO(q70qMMU9=yow$Ot#iDVe<lMbDCVLr_E?Ed7+*NH`tG0!esIRJy}M>
z$@lc0Xn@MoTdXOixdp{V8XzsIAVM8PfYMsgdZ=?IztWeI#8M1`3pVS?vIbja9>X=k
z3w&^1(qt<#nEcK_Ndas*m;eR!E&k$?#G;a7P}L94KAw{e48x>ML8gEm4=(ScK-_E)
zkvDmPp=$;>zCn>x1PVz=EQ2iu7qFlP8dB)M?JDADU|;~{>tax4#lgVA$RWeQ$HBqD
z!ok5I%TdN5!okJC%)!jT#=*|P$-%*)KiStvg3)ktno$g+>*T{mO0w~w7+@<%%u7iu
zE&>-x;GknpEG{VuoXlkGp$+zRImoHEK?JxCVJpZ?&dy0K0%iAG%*B<(x0v#ai=Iy|
yFxFwTpFGz%R~hU^1OW~i4x8Nkl+v73J5Y)!wwbJJV#vqAD8eMd$OFQRLd*cG@|rgQ

diff --git a/main/backend.py b/main/backend.py
index cb890d2..7382429 100644
--- a/main/backend.py
+++ b/main/backend.py
@@ -25,17 +25,30 @@ from matplotlib.dates import DateFormatter
 from matplotlib.lines import Line2D
 import json
 import plotly
+import zipfile
+import binascii
+
+
+from cryptography.exceptions import InvalidSignature
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import padding
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric import rsa
+from cryptography.hazmat.backends import default_backend
+
+import base64
 
 import time
 import pandas as pd
 from matplotlib.figure import Figure
 import datetime
 import plotly.graph_objects as go
+import plotly.io as pio
+
 from Decision import Decision
 
 import base64
 import io
-import settings
 
 
 from APIWrappers.ApiManagement import createOrder, createOrderLimit, deleteOrder, getBalance, getTicker, getOrders
@@ -44,9 +57,6 @@ from APIWrappers.ApiManagement import createOrder, createOrderLimit, deleteOrder
 
 async_mode = "eventlet"
 app = Flask(__name__)
-
-# app.config['SECRET_KEY'] = 'secret!'
-
 socket_ = SocketIO(app, async_mode=async_mode,cors_allowed_origins="*")
 
 market = "BTCUSDT"
@@ -56,9 +66,16 @@ dec = Decision("simulated",market)
 simulationInProgress = False
 
 dictError = {}
-stickyForm = dict(takeProfit='3.0',stopLoss='3.0',dateSimStart='2022-02-05',dateSimEnd='2022-04-09',indicatorSelect='',MA1='20',MA2='40')
+stickyForm = dict(takeProfit='3.0',stopLoss='3.0',dateSimStart='2022-02-05',dateSimEnd='2022-04-09',indicatorSelect='',MA1='20',MA2='40',minimumTime='15',maximumTime='60')
 resetParams = 1
-
+lstSimulations = []
+lstErrorSimulations = []
+showImportError = False
+figJson = None
+fig = None
+results = None
+nbrDoublons = 0
+indicatorSim = None
 
 @app.route('/')
 def index():
@@ -66,18 +83,21 @@ def index():
     global dictError
     global stickyForm
     global resetParams
-    
-    figJson = None
+    global figJson
+    global results
     results = None
+    figJson = None
     if resetParams == 1:
-        stickyForm = dict(takeProfit='3.0',stopLoss='3.0',dateSimStart='2022-02-05',dateSimEnd='2022-04-09',indicatorSelect='',MA1='20',MA2='40')
+        stickyForm = dict(takeProfit='3.0',stopLoss='3.0',dateSimStart='2022-02-05',dateSimEnd='2022-04-09',indicatorSelect='',MA1='20',MA2='40',minimumTime='15',maximumTime='60')
         
     if dec.export_result != []:
         simulationInProgress = False
         # figJson = createFig(dec.sim.histo_prices, dec.sim.active_orders, dec.sma[market], dec.mas[0], market)
         tmpOrder = [dec.sim.winsAV, dec.sim.lossAV, dec.sim.winsVA, dec.sim.lossVA]
-        # print(tmpOrder)
-        figJson = createFigPyplot(market,dec.sma[market], dec.mas[0], tmpOrder)
+        if indicatorSim == "SMA":
+            figJson = createFigPyplot(market,tmpOrder, mas=dec.sma[market], arraySma=dec.mas[0])
+        if indicatorSim == "random":
+            figJson = createFigPyplot(market,tmpOrder)
         results = getResults()
     reponse = make_response(render_template('index.html', async_mode=socket_.async_mode, inProgress=simulationInProgress, fig=figJson, res=results, err=dictError, stickyForm=stickyForm))
     # reponse.headers['Content-Security-Policy'] = "style-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com/ajax/libs/plotly.js/2.5.1/plotly.min.js https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js https://fonts.googleapis.com/ https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css"
@@ -86,6 +106,24 @@ def index():
     dictError = {}
     return reponse
 
+@app.route('/mySimulation')
+def mySimulation():
+    global showImportError
+    global lstErrorSimulations
+    global nbrDoublons
+    
+    if lstSimulations == []:
+        print("lstSimulations is empty")
+        return redirect("/importSimulation")
+    
+    if showImportError == False:
+        print("showImportError is False")
+        lstErrorSimulations = []
+        nbrDoublons = 0
+    if showImportError:
+        print("showImportError is True")
+        showImportError = False
+    return render_template('mySimulation.html', lstSimulations=lstSimulations, err=lstErrorSimulations, doublons=nbrDoublons)
 
 @app.route("/startSimulation", methods=["POST"])
 def startSimulation():
@@ -94,8 +132,8 @@ def startSimulation():
     global simulationInProgress
     global stickyForm
     global resetParams
+    global indicatorSim
     resetParams = 2
-    # genral input
     stickyForm = request.form.to_dict()
     tp = request.form.get("takeProfit")
     sl = request.form.get("stopLoss")
@@ -104,6 +142,8 @@ def startSimulation():
     dateSimStart = request.form.get("dateSimStart") + " 00:00:00.000000Z"
     dateSimEnd = request.form.get("dateSimEnd") + " 23:59:59.000000Z"
     ma = None
+    timeMin = 0
+    timeMax = 0
     
     indicator = request.form.get("indicatorSelect")
     if indicator == "SMA":
@@ -113,7 +153,13 @@ def startSimulation():
             ma = [int(ma1),int(ma2)]
         except:
             return redirect(request.referrer)
-    else: 
+    elif indicator == "random":
+        try:
+            timeMin = int(request.form.get("minimumTime"))
+            timeMax = int(request.form.get("maximumTime"))
+        except:
+            return redirect(request.referrer)
+    else:
         return redirect(request.referrer)
     try:
         tp = float(tp)
@@ -122,11 +168,11 @@ def startSimulation():
     except:
         return redirect(request.referrer)
     
-    dictError = checkGeneralInput(tp, sl, candleSize, dateSimStart, dateSimEnd, indicator, ma)
+    dictError = checkGeneralInput(tp, sl, candleSize, dateSimStart, dateSimEnd, indicator, ma, timeMin, timeMax)
     
     tp = tp/100
     sl = sl/100
-    
+    timeRandom = [timeMin, timeMax]
     dictValue = dictError.values()
     if 'is-invalid' in dictValue:
         return redirect(request.referrer)
@@ -136,21 +182,171 @@ def startSimulation():
     
     if not simulationInProgress:
         resetParams = 0
-        settings.init()
         dec.resetLists(market)
         simulationInProgress = True
-        thread = Thread(target=dec.launch, args=(dateSimStart,dateSimEnd,False,sl,tp,candleSize,ma))
+        indicatorSim = indicator
+        thread = Thread(target=dec.launch, args=(dateSimStart,dateSimEnd,indicator,False,sl,tp,candleSize,ma,timeRandom))
         thread.start()
     return redirect(request.referrer)
 
+@app.route("/importSimulation")
+def importSimulation():
+    global showImportError
+    global lstErrorSimulations
+    global nbrDoublons
+    if showImportError == False:
+        lstErrorSimulations = []
+        nbrDoublons = 0
+    if showImportError:
+        showImportError = False
+    return render_template('importSimulation.html', err=lstErrorSimulations, doublons=nbrDoublons)
+
+@app.route("/uploadFile", methods=["POST"])
+def uploadFile():
+    global lstSimulations
+    global lstErrorSimulations
+    global showImportError
+    global nbrDoublons
+    nbrDoublons = 0
+    lstErrorSimulations = []
+    showImportError = True
+    files = request.files.getlist('fileInput')
+    files += request.files.getlist('filesDragAndDrop')
+    for file in files:
+        filename = file.filename
+        fileExtension = os.path.splitext(filename)[1].lower()
+        file.seek(0)
+
+        typeOfFile = file.content_type
+            
+        if fileExtension not in ['.json', '.zip']:
+            lstErrorSimulations.append("L'extension du fichier n'est pas prise en charge.")
+            continue
+        if typeOfFile == "application/json":
+            fileData = file.read()
+            try:
+                fileData = fileData.decode('utf-8')
+            except UnicodeDecodeError:
+                lstErrorSimulations.append("Le fichier JSON ("+ file.filename +") n'est pas encodé en UTF-8.")
+                continue
+            try:
+                jsonFile = json.loads(fileData)
+                if 'signature' not in jsonFile:
+                    lstErrorSimulations.append("Le fichier JSON ("+ file.filename +") ne contient pas de signature.")
+                    continue
+                try:
+                    signature = base64.b64decode(jsonFile.pop('signature'))
+                    dataStr = json.dumps(jsonFile, sort_keys=True)
+                except:
+                    lstErrorSimulations.append("La signature du fichier JSON ("+ file.filename +") n'est pas correcte.")
+                    continue
+                try:
+                    publicKey.verify(
+                        signature=signature,
+                        data=dataStr.encode(),
+                        padding=padding.PSS(
+                            mgf=padding.MGF1(hashes.SHA256()),
+                            salt_length=padding.PSS.MAX_LENGTH
+                        ),
+                        algorithm=hashes.SHA256()
+                    )
+                    for profit in jsonFile['res']['moneyProfits']:
+                        jsonFile['res']['moneyProfits'][profit] = float(jsonFile['res']['moneyProfits'][profit])
+                    for losse in jsonFile['res']['moneyLosses']:
+                        jsonFile['res']['moneyLosses'][losse] = float(jsonFile['res']['moneyLosses'][losse])
+                    jsonFile['filename'] = file.filename
+                    lstSimulations.append(jsonFile)
+                except InvalidSignature:
+                    lstErrorSimulations.append("La signature du fichier JSON ("+ file.filename +") n'est pas correcte.")
+                    continue
+            except json.JSONDecodeError:
+                lstErrorSimulations.append("Le contenu du fichier JSON ("+ file.filename +") n'est pas valide.")
+                continue
+        elif typeOfFile == "application/zip":
+            nameZIP = filename
+            try:
+                fileData = file.read()
+                z = zipfile.ZipFile(io.BytesIO(fileData))
+                for filename in z.namelist():
+                    if filename.startswith('__MACOSX/'):
+                        continue
+                    if not filename.endswith('.json'):
+                        lstErrorSimulations.append("Le fichier ZIP ("+nameZIP+") contient un fichier non JSON ("+ filename +").")
+                        continue
+                    json_data = z.read(filename)
+                    try:
+                        json_data = json_data.decode("utf-8")
+                        jsonFile = json.loads(json_data)
+                        if 'signature' not in jsonFile:
+                            lstErrorSimulations.append("Le fichier JSON ("+ filename +") dans le ZIP ("+nameZIP+") ne contient pas de signature.")
+                            continue
+                        try:
+                            signature = base64.b64decode(jsonFile.pop('signature'))
+                            dataStr = json.dumps(jsonFile, sort_keys=True)
+                        except:
+                            lstErrorSimulations.append("La signature du fichier JSON ("+ filename +") dans le ZIP ("+nameZIP+") n'est pas correcte.")
+                            continue
+                        try:
+                            publicKey.verify(
+                                signature=signature,
+                                data=dataStr.encode(),
+                                padding=padding.PSS(
+                                    mgf=padding.MGF1(hashes.SHA256()),
+                                    salt_length=padding.PSS.MAX_LENGTH
+                                ),
+                                algorithm=hashes.SHA256()
+                            )
+                        except InvalidSignature:
+                            lstErrorSimulations.append("La signature du fichier JSON ("+ filename +") dans le ZIP ("+nameZIP+") n'est pas correcte.")
+                            continue
+                        for profit in jsonFile['res']['moneyProfits']:
+                            jsonFile['res']['moneyProfits'][profit] = float(jsonFile['res']['moneyProfits'][profit])
+                        for losse in jsonFile['res']['moneyLosses']:
+                            jsonFile['res']['moneyLosses'][losse] = float(jsonFile['res']['moneyLosses'][losse])
+                        jsonFile['filename'] = filename
+                        lstSimulations.append(jsonFile)
+                    except json.JSONDecodeError:
+                        lstErrorSimulations.append("Le contenu du fichier JSON ("+ filename +") dans le ZIP ("+nameZIP+") n'est pas valide.")
+                        continue
+            except zipfile.BadZipFile:
+                lstErrorSimulations.append("Le fichier ZIP ("+ filename +") est invalide ou corrompu.")
+                continue
+        else:
+            lstErrorSimulations.append("Le format du fichier ("+ filename +") n'est pas pris en charge.")
+            continue
+    nbrDoublons = 0
+    i = 0
+    while i < len(lstSimulations):
+        j = i + 1
+        while j < len(lstSimulations):
+            if lstSimulations[i]['params'] == lstSimulations[j]['params']:
+                print("doublon supp : ", lstSimulations[j]['filename'])
+                del lstSimulations[j]
+                nbrDoublons += 1
+            else:
+                j += 1
+        i += 1
+    return jsonify({'nbrFileUpload': len(lstSimulations)})
 
 
 @app.route("/progress")
 def progress():
-    if settings.progressBar < 60:
-        settings.progressBar += 4
-    return jsonify({'progress': settings.progressBar})
+    if dec.sim.progressBar < 60:
+        dec.sim.progressBar += 4
+    return jsonify({'progress': dec.sim.progressBar})
 
+@app.route("/deleteSimulation", methods=["GET"])
+def deleteSimulation():
+    global lstSimulations
+    
+    index = request.args.get('index')
+    try:
+        index = int(index)
+        if index < len(lstSimulations):
+            del lstSimulations[index]
+    except:
+        return redirect('/mySimulation')
+    return redirect('/mySimulation')
 
 @app.route("/resetSimulation")
 def resetSimulation():
@@ -175,8 +371,60 @@ def resetSimulationWithParams():
     
     return redirect('/')
 
+@app.route("/restartSimulationWithParamsFromIndex")
+def restartSimulationWithParamsFromIndex():
+    global simulationInProgress
+    global resetParams
+    global lstSimulations
+    global stickyForm
+    
+    index = request.args.get('index')
+    try:
+        index = int(index)
+    except:
+        return redirect('/mySimulation')
+    if not simulationInProgress:
+        if index >= len(lstSimulations):
+            return redirect('/mySimulation')
+        params = lstSimulations[index]['params']
+        stickyForm = params
+        resetParams = 0
+        dec.export_result = []
+    
+    return redirect('/')
+
+@app.route("/signJSON", methods=["POST"])
+def signJSON():
+    global results
+    if fig != None:
+        image = request.get_json()
+        resultsCopy = results
+        for profit in resultsCopy['moneyProfits']:
+            resultsCopy['moneyProfits'][profit] = str(resultsCopy['moneyProfits'][profit])
+        for losse in resultsCopy['moneyLosses']:
+            resultsCopy['moneyLosses'][losse] = str(resultsCopy['moneyLosses'][losse])
+        jsonData = {
+            'image': image['image'],
+            'res': resultsCopy,
+            'params': stickyForm,
+        }
+        jsonData = json.dumps(jsonData, sort_keys=True)
+        signature = privateKey.sign(
+            data=jsonData.encode(),
+            padding=padding.PSS(
+                mgf=padding.MGF1(hashes.SHA256()),
+                salt_length=padding.PSS.MAX_LENGTH
+            ),
+            algorithm=hashes.SHA256()
+        )
+        base64Signature = base64.b64encode(signature).decode()
+        jsonData = json.loads(jsonData)
+        jsonData['signature'] = base64Signature
+        return jsonify(jsonData)
+    return jsonify({})
+
 
-def checkGeneralInput(takeprofit, stoploss, candleSize, dateSimStart, dateSimEnd, indicator, ma):
+def checkGeneralInput(takeprofit, stoploss, candleSize, dateSimStart, dateSimEnd, indicator, ma, timeMin, timeMax):
     dictError = {}
     # Check if takeprofit and stoploss are between 0 and 100
     if takeprofit > 100 or takeprofit < 1:
@@ -207,9 +455,16 @@ def checkGeneralInput(takeprofit, stoploss, candleSize, dateSimStart, dateSimEnd
             dictError['ma'] = 'is-invalid'
         else:
             dictError['ma'] = 'is-valid'
+    elif indicator == "random":
+        if timeMin > timeMax or timeMin < 15 or timeMax > 1440 or timeMax < timeMin or timeMin == timeMax:
+            dictError['random'] = 'is-invalid'
+        else:
+            dictError['random'] = 'is-valid'
     return dictError
 
-def createFigPyplot(market, mas, arraySma, orders):
+def createFigPyplot(market, orders, mas=[], arraySma=[]):
+    global fig
+    
     dataChart = dec.sim.candle_prices
 
     months = {"January": "Janvier", "February": "Février", "March": "Mars", "April": "Avril", "May": "Mai", "June": "Juin", "July": "Juillet", "August": "Août", "September": "Septembre", "October": "Octobre", "November": "Novembre", "December": "Décembre"}
@@ -241,27 +496,26 @@ def createFigPyplot(market, mas, arraySma, orders):
             name="Prix"
             
         )])
-    
-    smaData = {sma: {'price': [], 'date': []} for sma in arraySma}
-    for sma, values in mas.items():
-        for value in values:
-            smaData[int(sma)]['price'].append(value[0])
-            smaData[int(sma)]['date'].append(value[1])
-
-    for i, sma in enumerate(arraySma):
-        fig.add_trace(
-            go.Scatter(
-                x=smaData[sma]['date'],
-                y=smaData[sma]['price'],
-                mode='lines',
-                name=f'SMA{sma}',
-                hoverinfo="none",
-                line=dict(color=['rgba(0, 0, 255, 0.3)', 'rgba(128, 0, 128, 0.3)'][i])
+    if indicatorSim == "SMA":
+        smaData = {sma: {'price': [], 'date': []} for sma in arraySma}
+        for sma, values in mas.items():
+            for value in values:
+                smaData[int(sma)]['price'].append(value[0])
+                smaData[int(sma)]['date'].append(value[1])
+
+        for i, sma in enumerate(arraySma):
+            fig.add_trace(
+                go.Scatter(
+                    x=smaData[sma]['date'],
+                    y=smaData[sma]['price'],
+                    mode='lines',
+                    name=f'SMA{sma}',
+                    hoverinfo="none",
+                    line=dict(color=['rgba(0, 0, 255, 0.3)', 'rgba(128, 0, 128, 0.3)'][i])
+                )
             )
-        )
 
     avWins, avLoss, vaWins, vaLoss = orders
-    print(avWins)
 
     for data, color, symbol, name, endName in [
         (avWins, 'green', 'triangle-up', 'AV Gains', 'Fin AV Gains'),
@@ -279,7 +533,8 @@ def createFigPyplot(market, mas, arraySma, orders):
                 marker=dict(
                     symbol=symbol,
                     size=17,
-                    color=color
+                    color=color,
+                    line=dict(color='blue', width=1)
                 ),
                 legendgroup=name
             )
@@ -315,20 +570,21 @@ def createFigPyplot(market, mas, arraySma, orders):
                 )
             )
     fig.update_layout(
+        margin=dict(l=10, r=10, t=50, b=10),
         xaxis_rangeslider_visible=False,
         title="Simulation sur le marché " + market,
         xaxis_title="Date",
         yaxis_title="Prix",
         hovermode="closest",
+        plot_bgcolor='#f2f2f2',
         hoverlabel=dict(
             bgcolor="rgba(123, 132, 144, 0.4)",
             font_size=16,
             align="auto",
         )
     )
-    fig.update_layout(plot_bgcolor='#f2f2f2')
     fig.update_yaxes(fixedrange=False)
-    fig.update_layout()
+    # fig.update_layout()
     figJson = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)
     return figJson
 
@@ -337,17 +593,7 @@ def createFig(prices,orders,mas,periodes,market):
             
     prices = dec.sim.histo_prices
     prices=pd.DataFrame(prices,columns=['price','date'])
-    
-    print(prices)
-    print("//////////////////////////////// -> orders")
-    print(orders)
-    print("//////////////////////////////// -> mas")
-    print(mas)
-    print("//////////////////////////////// -> periodes")
-    print(periodes)
-    print("//////////////////////////////// -> market")
-    
-    print(market)
+
     figJson= dec.sim.candle_prices
     
     fig = go.Figure()
@@ -442,6 +688,40 @@ def getResults():
                 dict['moneyLosses'][i] = dict['startBalance'][i] * (round(dict['losses'][j],2) * 0.01)
     return dict
 
+def getKeys():
+    privateKeyPath = "privateKey.pem"
+    publicKeyPath = "publicKey.pem"
+
+    if os.path.exists(privateKeyPath) and os.path.exists(publicKeyPath):
+        with open(privateKeyPath, "rb") as key_file:
+            privateKey = serialization.load_pem_private_key(
+                data=key_file.read(),
+                password=None
+            )
+        with open(publicKeyPath, "rb") as key_file:
+            publicKey = serialization.load_pem_public_key(
+                data=key_file.read()
+            )
+    else:
+        privateKey = rsa.generate_private_key(public_exponent=65537, key_size=2048)
+        publicKey = privateKey.public_key()
+
+        with open(privateKeyPath, "wb") as key_file:
+            key_file.write(privateKey.private_bytes(
+                encoding=serialization.Encoding.PEM,
+                format=serialization.PrivateFormat.PKCS8,
+                encryption_algorithm=serialization.NoEncryption()
+            ))
+
+        with open(publicKeyPath, "wb") as key_file:
+            key_file.write(publicKey.public_bytes(
+                encoding=serialization.Encoding.PEM,
+                format=serialization.PublicFormat.SubjectPublicKeyInfo
+            ))
+    
+    return privateKey, publicKey
+
+privateKey, publicKey = getKeys()
 
 
 # #Route wallet ==> order creation
diff --git a/main/settings.py b/main/settings.py
deleted file mode 100644
index 87bf53a..0000000
--- a/main/settings.py
+++ /dev/null
@@ -1,3 +0,0 @@
-def init():
-    global progressBar
-    progressBar = 0
\ No newline at end of file
diff --git a/main/simulation.py b/main/simulation.py
index 4100240..1f08122 100644
--- a/main/simulation.py
+++ b/main/simulation.py
@@ -28,7 +28,6 @@ import random
 import numpy.polynomial.polynomial as poly
 import pickle
 
-import settings
 import sys
 import os
 
@@ -67,7 +66,9 @@ class Simulation:
         self.end_Active = 0
         self.base = base
         self.target = target
-
+        self.progressBar = 0
+        self.orderFinished = True
+        
     #Get closing prices and date from histo_candles into 1 list
     def reformatPrices(self):
         print("REFORMAT PRICES")
@@ -129,7 +130,8 @@ class Simulation:
         self.market = market
         self.start_time =dt.now()
         self.candle_prices = []
-
+        self.progressBar = 0
+        self.orderFinished = True
 
     #Get ochl candle and polynomial transform to get a price ticker and a given time periode
     def calcOCLH(self,slices_sec,periode_base,format,symbol,show_graph,dateStart,dateEnd):
@@ -147,7 +149,8 @@ class Simulation:
             self.histo_candles = getHistoCandles(symbol,dateStart, dateEnd)
             # print(self.histo_candles)
             candles = self.histo_candles
-        pourcentage = settings.progressBar 
+        # pourcentage = settings.progressBar 
+        pourcentage = self.progressBar
         for c in candles:
             Candles = {}
             xs=[]
@@ -176,7 +179,8 @@ class Simulation:
             totalDuration = (tmpDateEnd - tmpDateStart).total_seconds()
             elapsedDuration = (currentDate - tmpDateStart).total_seconds()
             
-            settings.progressBar = pourcentage + (elapsedDuration / totalDuration) * (95-pourcentage)
+            # settings.progressBar = pourcentage + (elapsedDuration / totalDuration) * (95-pourcentage)
+            self.progressBar = pourcentage + (elapsedDuration / totalDuration) * (95-pourcentage)
             # print(percentage)
             #print(f"DATE Candle : {dt.fromtimestamp(date)}")
             date = dt.fromtimestamp(date) - datetime.timedelta(0,periode_base)
@@ -264,6 +268,7 @@ class Simulation:
             
             return self.end_Active
         else:
+            # self.orderFinished = True
             # print("Can't place, 1 order is still active")
             # print("End active : ",self.end_Active)
             return self.end_Active
@@ -359,7 +364,8 @@ class Simulation:
         "VA_loss" : nb_lossVA,"avg_time_order":self.avgtime_order,
         "losses": losses, "profits":profits}
         print(res)
-        settings.progressBar = 100
+        self.progressBar = 100
+        # settings.progressBar = 100
         return res
 
     #Calculate profit of the simulation
diff --git a/main/static/.DS_Store b/main/static/.DS_Store
index a31724f9a298e95e1f177e5a6234051e3051b4af..3c2f395e2e1ed09fb39bc71d99c2a344f0d5ac21 100644
GIT binary patch
delta 47
zcmZoMXffCj%*423atKo)w?uWdk)?%>g0Z3L<nv6@j9rsoGs!b{Z{}wH&9a%D<1aq|
DVL}e&

delta 46
zcmZoMXffCj%*42TatKo)mw0uxv9Xzsg1PzR3ry0Cos-`%$uo9s=3)NLvYCzJA3p$9
CV-B$Z

diff --git a/main/templates/base.html b/main/templates/base.html
index 391fa2e..53540b6 100644
--- a/main/templates/base.html
+++ b/main/templates/base.html
@@ -14,7 +14,6 @@
 </head>
 
 <body id="page-top" class="d-flex flex-column min-vh-100">
-    <!-- Navigation-->
     <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" id="mainNav">
         <div class="container px-4">
             <a class="navbar-brand" href="{{ url_for('index')}}">Silmulateur de trading de cryptomonnaies</a>
@@ -23,8 +22,7 @@
                     class="navbar-toggler-icon"></span></button>
             <div class="collapse navbar-collapse" id="navbarResponsive">
                 <ul class="navbar-nav ms-auto">
-                    <!-- <li class="nav-item"><a class="nav-link" href="#launchSimulation">Démarrer une simulation</a></li> -->
-                    <li class="nav-item"><a class="nav-link" href="#simulations">Mes simulations</a></li>
+                    <li class="nav-item"><a class="nav-link" href="{{ url_for('mySimulation') }}">Mes simulations</a></li>
                     <li class="nav-item"><a class="nav-link" href="#comparaison">Comparaison</a></li>
                 </ul>
             </div>
@@ -32,8 +30,7 @@
     </nav>
     {% block content %}
     {% endblock %}
-    <!-- Footer-->
-    <footer class="py-5 bg-dark">
+    <footer class="py-4 bg-dark">
         <div class="container-fluid px-4">
             <div class="row justify-content-center">
                 <div class="col-12 text-center">
@@ -42,7 +39,6 @@
             </div>
         </div>
     </footer>
-    <!-- Bootstrap core JS-->
     <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
 </body>
 </html>
\ No newline at end of file
diff --git a/main/templates/importSimulation.html b/main/templates/importSimulation.html
new file mode 100644
index 0000000..a16d02a
--- /dev/null
+++ b/main/templates/importSimulation.html
@@ -0,0 +1,154 @@
+{% extends 'base.html' %}
+{% block content %}
+<section class="gradient-custom p-5 h-100 align-items-center my-auto">
+    <div class="container py-5 h-100">
+        <div class="row justify-content-center align-items-center h-100">
+            <div class="col-12 col-lg-9 col-xl-7">
+                <h3 class="mb-4 pb-2 pb-md-0 mb-md-2">Importation de simulations</h3>
+                <div class="card shadow-2-strong card-registration" style="border-radius: 15px;">
+                    <div class="card-body p-4 p-md-5 dropzone" ondragover="handleDragOver(event)">
+                        <form action="uploadFile" method="post" enctype="multipart/form-data">
+                            <div class="container">
+                                <div class="row">
+                                    <div class="col-lg-12">
+                                        <div class="text-center">
+                                            <h3>Faites glisser et déposez les fichiers JSON ou ZIP ici</h3>
+                                            <i class="bi bi-cloud-upload"></i>
+                                            <p>Ou sélectionnez les fichiers en cliquant ici :</p>
+                                            <input class="form-control form-control-sm w-50 mx-auto" type="file"
+                                                name="fileInput" accept=".json,.zip" capture="*.json,*.zip" multiple>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                            <br>
+                            <table id="fileTable" class="table"></table>
+                    </div>
+                </div>
+                <br>
+                {% for error in err %}
+                <div class="alert alert-danger alert-dismissible fade show" role="alert">
+                    {{ error }}
+                    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
+                </div>
+                {% endfor %}
+                <div class="row text-center">
+                    <div class="mt-4 pt-2">
+                        <button type="submit" class="btn btn-primary btn-lg">Envoyer</button>
+                    </div>
+                </div>
+                </form>
+            </div>
+        </div>
+    </div>
+</section>
+<script>
+    var filesToUpload = [];
+
+    function handleDragOver(event) {
+        event.preventDefault();
+        event.dataTransfer.dropEffect = 'move';
+        document.querySelector('.dropzone').style.backgroundColor = '#f2f2f2';
+        document.querySelector('.dropzone').style.borderRadius = '15px';
+    }
+
+    function handleDragLeave(event) {
+        event.preventDefault();
+        document.querySelector('.dropzone').style.backgroundColor = '';
+    }
+
+    function handleDrop(event) {
+        event.preventDefault();
+
+        var files = event.dataTransfer.files;
+        for (var i = 0, f; f = files[i]; i++) {
+            if (!['application/json', 'application/zip'].includes(f.type)) {
+                alert('Type de fichier invalide. Veuillez uploader un fichier JSON ou ZIP.');
+                continue;
+            }
+
+            filesToUpload.push(f);
+            createFileElement(f);
+        }
+
+        document.querySelector('.dropzone').style.backgroundColor = '';
+    }
+
+    function createFileElement(file) {
+        var row = document.createElement('tr');
+
+        var fileName = document.createElement('td');
+        fileName.textContent = file.name;
+        row.appendChild(fileName);
+
+        var removeFile = document.createElement('td');
+        var trashIcon = document.createElement('i');
+        trashIcon.classList.add('bi');
+        trashIcon.classList.add('bi-trash');
+        removeFile.appendChild(trashIcon);
+
+
+        removeFile.style.color = 'red';
+        removeFile.style.cursor = 'pointer';
+        removeFile.style.textAlign = 'right';
+        removeFile.addEventListener('click', function (e) {
+            var index = filesToUpload.indexOf(file);
+            if (index > -1) {
+                filesToUpload.splice(index, 1);
+            }
+            row.remove();
+        });
+        row.appendChild(removeFile);
+
+        row.style.borderBottom = '1px solid #000';
+        row.style.borderTop = '1px solid #000';
+    
+        document.querySelector('#fileTable').appendChild(row);
+    }
+
+
+    function handleSubmit(event) {
+        event.preventDefault();
+
+        var fileInput = document.querySelector('input[name="fileInput"]');
+
+        for (var i = 0, f; f = fileInput.files[i]; i++) {
+            if (!['application/json', 'application/zip'].includes(f.type)) {
+                alert('Type de fichier invalide. Veuillez uploader un fichier JSON ou ZIP.');
+                continue;
+            }
+            filesToUpload.push(f);
+        }
+
+        var formData = new FormData();
+
+        for (var i = 0, f; f = filesToUpload[i]; i++) {
+            formData.append('filesDragAndDrop', f, f.name);
+        }
+
+        fetch('uploadFile', { method: 'POST', body: formData })
+        .then(response => response.json())
+        .then(data => {
+            filesToUpload = [];
+            fileInput.value = '';
+    
+            window.location.href = "/mySimulation";
+        })
+        .catch(error => {
+            console.error('Erreur:', error);
+        });
+        
+
+    }
+
+    var dropzone = document.querySelector('.dropzone');
+    dropzone.addEventListener('dragover', handleDragOver, false);
+    dropzone.addEventListener('dragleave', handleDragLeave, false);
+    dropzone.addEventListener('drop', handleDrop, false);
+
+    var submitButton = document.querySelector('button[type="submit"]');
+    submitButton.addEventListener('click', handleSubmit, false);
+
+    dropzone.style.overflowY = 'scroll';
+</script>
+{% endblock %}
\ No newline at end of file
diff --git a/main/templates/index.html b/main/templates/index.html
index b93db00..9bbb17b 100644
--- a/main/templates/index.html
+++ b/main/templates/index.html
@@ -115,11 +115,11 @@
                                             {% else %}
                                             <option value="random">Aléatoire</option>
                                             {% endif %}
-                                            {% if stickyForm['indicatorSelect'] == 'test' %}
+                                            <!-- {% if stickyForm['indicatorSelect'] == 'test' %}
                                             <option value="test" selected>test</option>
                                             {% else %}
                                             <option value="test">test</option>
-                                            {% endif %}
+                                            {% endif %} -->
                                         </select>
                                         <div class="valid-feedback">
                                             Correct !
@@ -167,17 +167,35 @@
                             <div class="row" id="rowRandom" style="display: none;">
                                 <div class="col-md-6 mb-4">
                                     <div class="form-outline">
-                                        <label class="form-label" for="M">Random</label>
-                                        <input type="number" class="form-control form-control-lg" id="MA1" name="MA1"
-                                            max="100" min="5" value="20" step="5">
+                                        <label class="form-label" for="minimumTime">Temps aléatoire minimum
+                                            (minute)</label>
+                                        <input type="number" class="form-control form-control-lg {{ err['random'] }}"
+                                            id="minimumTime" name="minimumTime" max="1440" min="15"
+                                            value="{{ stickyForm['minimumTime']}}" step="5">
+                                        <div class="valid-feedback">
+                                            Correct !
+                                        </div>
+                                        <div class="invalid-feedback">
+                                            Veuillez entrer un nombre entre 15 et 1440 minutes. Le temps aléatoire minimum
+                                            doit être plus petit que le maximum.
+                                        </div>
                                     </div>
 
                                 </div>
                                 <div class="col-md-6 mb-4">
                                     <div class="form-outline">
-                                        <label class="form-label" for="M">Random</label>
-                                        <input type="number" class="form-control form-control-lg" id="MA2" name="MA2"
-                                            max="105" min="10" value="40" step="5">
+                                        <label class="form-label" for="maximumTime">Temps aléatoire maximum
+                                            (minute)</label>
+                                        <input type="number" class="form-control form-control-lg {{ err['random'] }}"
+                                            id="maximumTime" name="maximumTime" max="1440" min="15"
+                                            value="{{ stickyForm['maximumTime']}}" step="5">
+                                        <div class="valid-feedback">
+                                            Correct !
+                                        </div>
+                                        <div class="invalid-feedback">
+                                            Veuillez entrer un nombre entre 15 et 1440 minutes. Le temps aléatoire minimum
+                                            doit être plus petit que le maximum.
+                                        </div>
                                     </div>
 
                                 </div>
@@ -200,8 +218,12 @@
 
                                 </div>
                             </div>
-                            <div class="row text-center">
-                                <div class="mt-4 pt-2">
+                            <div class="row">
+                                <div class="col-md-6 mb-4">
+                                    <a href="resetSimulation"><button type="button"
+                                            class="btn btn-secondary btn-lg">Réinitialiser les paramètres</button></a>
+                                </div>
+                                <div class="col-md-6 mb-4">
                                     <button type="submit" class="btn btn-primary btn-lg">Lancer la simulation</button>
                                 </div>
                             </div>
@@ -281,13 +303,11 @@
                             résultats</button>
                     </div>
                     <div class="col-sm mb-4 text-center">
-                        <!-- Button trigger modal -->
                         <button type="button" class="btn btn-primary btn-lg" data-bs-toggle="modal"
                             data-bs-target="#modalSimulation">
                             Démarrer une nouvelle simulation
                         </button>
 
-                        <!-- Modal -->
                         <div class="modal fade" id="modalSimulation" tabindex="-1" aria-hidden="true">
                             <div class="modal-dialog">
                                 <div class="modal-content">
@@ -396,23 +416,23 @@
     const SMA = document.getElementById('rowSMA');
     const random = document.getElementById('rowRandom');
     const test = document.getElementById('rowTest');
-    
+
     var inProgress = {{ inProgress| lower }};
     var chart = null;
 
     {% if fig != None %}
-        chart = {{ fig | safe }};
-        Plotly.plot("chart", chart, {});
-        showMoreInfo.addEventListener('click', function () {
-            if (moreResults.style.display === 'none') {
-                moreResults.style.display = 'block';
-                showMoreInfo.innerHTML = 'Masquer les résultats';
-            } else {
-                moreResults.style.display = 'none';
-                showMoreInfo.innerHTML = 'Afficher plus de résultats';
-            }
-        });
-        exportSimulation.addEventListener('click', exportFile);
+    chart = {{ fig | safe }};
+    Plotly.plot("chart", chart, {});
+    showMoreInfo.addEventListener('click', function () {
+        if (moreResults.style.display === 'none') {
+            moreResults.style.display = 'block';
+            showMoreInfo.innerHTML = 'Masquer les résultats';
+        } else {
+            moreResults.style.display = 'none';
+            showMoreInfo.innerHTML = 'Afficher plus de résultats';
+        }
+    });
+    exportSimulation.addEventListener('click', exportFile);
 
     {% endif %}
 
@@ -455,29 +475,64 @@
         }
     }
 
-    function exportFile() {
-        Plotly.toImage(document.getElementById('chart'), { format: 'png' })
-        .then(function(dataUrl){
-            const filename = "{{ res['market'] }}.json";
-            const jsonData = {
-                image: dataUrl, 
-                res: {{ res | tojson }},
-                params: {{ stickyForm | tojson }}
+    async function exportFile() {
+        const chartElement = document.getElementById('chart');
+        const currentData = chartElement.data;
+        const currentLayout = chartElement.layout;
+
+        const newChartElement = document.createElement('div');
+        Plotly.newPlot(newChartElement, currentData, currentLayout);
+
+        const layout = {
+            margin: {
+                t: 20,
+                r: 20,
+                b: 20,
+                l: 20
+            }
+        };
+
+        Plotly.relayout(newChartElement, {
+            showlegend: false,
+            title: {
+                text: ''
             }
-            const jsonStr = JSON.stringify(jsonData);
-    
-            let element = document.createElement('a');
-            element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(jsonStr));
-            element.setAttribute('download', filename);
-    
-            element.style.display = 'none';
-            document.body.appendChild(element);
-    
-            element.click();
-    
-            document.body.removeChild(element);
-        })
+        });
+
+        Plotly.update(newChartElement, {}, layout);
+
+        Plotly.toImage(newChartElement, { format: 'png' })
+            .then(function (dataUrl) {
+                const filename = "{{ res['market'] }}.json";
+                const jsonData = {
+                    image: dataUrl,
+                };
+                const jsonStr = JSON.stringify(jsonData);
+
+                fetch('/signJSON', {
+                    method: 'POST',
+                    headers: {
+                        'Content-Type': 'application/json'
+                    },
+                    body: jsonStr
+                })
+                    .then(response => response.json())
+                    .then(signedJson => {
+                        const signedJsonStr = JSON.stringify(signedJson);
+                        let element = document.createElement('a');
+                        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(signedJsonStr));
+                        element.setAttribute('download', filename);
+
+                        element.style.display = 'none';
+                        document.body.appendChild(element);
+
+                        element.click();
+
+                        document.body.removeChild(element);
+                    });
+            });
     }
 
+
 </script>
 {% endblock %}
\ No newline at end of file
diff --git a/main/templates/mySimulation.html b/main/templates/mySimulation.html
new file mode 100644
index 0000000..925a336
--- /dev/null
+++ b/main/templates/mySimulation.html
@@ -0,0 +1,138 @@
+{% extends 'base.html' %}
+{% block content %}
+{% if lstSimulations != [] %}
+<section class="gradient-custom p-5 h-100 align-items-center my-auto">
+    <div class="album py-5">
+        <div class="container" style="padding: 0%; margin: 0%;">
+            {% for error in err %}
+            <div class="alert alert-danger alert-dismissible fade show" role="alert">
+                {{ error }}
+                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
+            </div>
+            {% endfor %}
+            {% if doublons != 0 %}
+            <div class="alert alert-warning alert-dismissible fade show" role="alert">
+                {{ doublons }} doublon(s) supprimé(s)
+                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
+            </div>
+            {% endif %}
+            <div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 g-3">
+                {% for simulation in lstSimulations %}
+                <div class="col">
+                    <div class="card shadow-sm">
+                        <h5 class="px-4 pt-4">Marché : {{ simulation['res']['market']}}</h5>
+                        <p class="px-4">{{ simulation['filename'] }}</p>
+                        <img src="{{ simulation['image']}}" class="bd-placeholder-img card-img-top" width="100%"
+                            height="225">
+                        <div class="card-body px-0">
+                            <div class="container h-100">
+                                <div class="row">
+                                    {% for symbol in simulation['res']['losses']|reverse %}
+                                    {% if symbol == "USDT" %}
+                                    <div class="col-md-6 mb-2">
+                                        <span class="badge badge-pill bg-danger">{{ symbol }}</span><span
+                                            style="color:red">
+                                            {{ simulation['res']['moneyLosses'][symbol]|round(2)|string
+                                            }}₮ ({{ simulation['res']['losses'][symbol]|round(2)|string+"%" }})</span>
+                                    </div>
+                                    {% elif symbol == "BTC" %}
+                                    <div class="col-md-6 mb-2" style="padding-right: 0%;">
+                                        <span class="badge badge-pill bg-danger">{{ symbol }}</span><span
+                                            style="color:red">
+                                            {{
+                                            "{:.5f}".format(simulation['res']['moneyLosses'][symbol])|string
+                                            }}₿ ({{ simulation['res']['losses'][symbol]|round(2)|string+"%" }})</span>
+                                    </div>
+                                    {% endif %}
+                                    {% endfor %}
+
+                                    {% for symbol in simulation['res']['profits']|reverse %}
+                                    {% if symbol == "USDT" %}
+                                    <div class="col-md-6 mb-2">
+                                        <span class="badge badge-pill bg-success">{{ symbol }}</span><span
+                                            style="color:green"> +{{
+                                            simulation['res']['moneyProfits'][symbol]|round(2)|string
+                                            }}₮ ({{ simulation['res']['profits'][symbol]|round(2)|string+"%" }})</span>
+                                    </div>
+                                    {% elif symbol == "BTC" %}
+                                    <div class="col-md-6 mb-2" style="padding-right: 0%;">
+                                        <span class="badge badge-pill bg-success">{{ symbol }}</span><span
+                                            style="color:green"> +{{
+                                            "{:.5f}".format(simulation['res']['moneyProfits'][symbol])|string
+                                            }}₿ ({{ simulation['res']['profits'][symbol]|round(2)|string+"%" }})</span>
+                                    </div>
+                                    {% endif %}
+                                    {% endfor %}
+                                    {% if simulation['res']['profits'] == {} and simulation['res']['losses'] == {} %}
+                                    <span class="text-center mb-2">Aucun profit ou perte</span>
+                                    {% endif %}
+                                </div>
+                                <div class="row">
+                                    <div class="col-md-6 mb-2">
+                                        <span class="badge badge-pill bg-warning">Take Profit</span><span> {{
+                                            simulation['params']['takeProfit'] }}</span>
+                                    </div>
+                                    <div class="col-md-6 mb-2">
+                                        <span class="badge badge-pill bg-warning">Stop Loss</span><span> {{
+                                            simulation['params']['stopLoss'] }}</span>
+                                    </div>
+                                </div>
+                                <div class="row">
+                                    <div class="col-md-6 mb-2">
+                                        <span class="badge badge-pill bg-warning">Stratégie</span><span> {{
+                                            simulation['params']['indicatorSelect'] }}</span>
+                                    </div>
+                                    <div class="col-md-6 mb-2">
+                                        <span class="badge badge-pill bg-warning">Winrate</span><span> {{
+                                            simulation['res']['winrate'] }}%</span>
+                                    </div>
+                                </div>
+                                <br>
+                                <div class="row">
+                                    <div class="col-md-6 mb-2">
+                                        <a href="/deleteSimulation?index={{ loop.index-1 }}"
+                                            class="btn btn-sm btn-danger">Supprimer</a>
+                                    </div>
+                                    <div class="col-md-6 mb-2">
+                                        <a href="/restartSimulationWithParamsFromIndex?index={{ loop.index-1 }}"
+                                            class="btn btn btn-sm btn-primary">Relancer la simulation</a>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                {% endfor %}
+                {% if lstSimulations|length > 0 %}
+                <div class="col">
+                    <div class="card shadow-sm h-100">
+                        <div class="card-body px-0">
+                            <div class="container h-100">
+                                <div class="d-flex justify-content-center align-items-center" style="height: 100%;">
+                                    <a href="importSimulation"><i
+                                            class="bi bi-plus-square" id="logo" style="font-size: 70px; color:green;"></i></a>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+                <script>
+                    const logo = document.getElementById('logo');
+                    logo.addEventListener('mouseover', function () {
+                        logo.classList.remove('bi-plus-square');
+                        logo.classList.add('bi-plus-square-fill');
+                    });
+
+                    logo.addEventListener('mouseout', function () {
+                        logo.classList.remove('bi-plus-square-fill');
+                        logo.classList.add('bi-plus-square');
+                    });
+                </script>
+                {% endif %}
+            </div>
+        </div>
+    </div>
+    </div>
+</section>
+{% endif %}
+{% endblock %}
\ No newline at end of file
-- 
GitLab