diff --git a/main/Decision.py b/main/Decision.py index d72f7a216568ec79326e3f874c9030e700cf2d31..7ebc93db3b0f03e4d7cedc313834dfa8d5437547 100644 --- a/main/Decision.py +++ b/main/Decision.py @@ -95,7 +95,6 @@ class Decision: #Launch SMA calculation # Mettre les décisions - self.calculateSMA(date,symbol,price,mas) if self.indexTickerSim >= len(sim.histo_prices)-1: break @@ -140,7 +139,6 @@ class Decision: #If simulated ==> launch a bunch of tests print("SIMULATED") self.sim = Simulation(None,None,markets[0],bases[0],targets[0]) - #For each market apply lagrange to get the price of ohlc datas for i,market in enumerate(markets): self.sim.startsimulation("lagrange",market,show_graph,dateStart,dateEnd) diff --git a/main/__pycache__/Decision.cpython-310.pyc b/main/__pycache__/Decision.cpython-310.pyc index 7c3a489da670638c0d0e0964fa147338a8ae993d..1d77cd921b83a35d7cc3672a2ca5f7f4f160f4ef 100644 Binary files a/main/__pycache__/Decision.cpython-310.pyc and b/main/__pycache__/Decision.cpython-310.pyc differ diff --git a/main/__pycache__/simulation.cpython-310.pyc b/main/__pycache__/simulation.cpython-310.pyc index 837832285c085945277a863706f91789fac2e686..e6f8c914f44e21d1aee9d3a287b06ef1cb1f8865 100644 Binary files a/main/__pycache__/simulation.cpython-310.pyc and b/main/__pycache__/simulation.cpython-310.pyc differ diff --git a/main/backend.py b/main/backend.py index 54f8fb2e5531eb8fa025cbb78c6492773f2f6313..724be19da8592b09a8b87a0b5dc327ad9898584d 100644 --- a/main/backend.py +++ b/main/backend.py @@ -67,7 +67,6 @@ def index(): global stickyForm global resetParams - url = None figJson = None results = None if resetParams == 1: @@ -75,11 +74,13 @@ def index(): if dec.export_result != []: simulationInProgress = False - figJson = createFig(dec.sim.histo_prices, dec.sim.active_orders, dec.sma[market], dec.mas[0], market) - # url = 'static/imgSimulation/simulation.png' + # 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) results = getResults() - reponse = make_response(render_template('index.html', async_mode=socket_.async_mode, simulation=url, 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" + 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" if resetParams == 2: resetParams = 1 dictError = {} @@ -208,15 +209,150 @@ def checkGeneralInput(takeprofit, stoploss, candleSize, dateSimStart, dateSimEnd dictError['ma'] = 'is-valid' return dictError +def createFigPyplot(market, mas, arraySma, orders): + 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"} + + textHover = [] + for item in dataChart: + date = datetime.datetime.strptime(item["date"], '%Y-%m-%d %H:%M:%S') + formatted_date = date.strftime('%d %B \'%y\n%H:%M') + month = date.strftime('%B') + if month in months: + formatted_date = formatted_date.replace(month, months[month]) + formatted_date = '<br>'.join(formatted_date.split('\n')) + if item["close"] > item["open"]: + color = 'green' + else: + color = 'red' + + text = f"<span style='color: white;'>O</span> <span style='color: {color}'>{str(item['open'])}</span><br><span style='color: white;'>H</span> <span style='color: {color}'>{str(item['high'])}</span><br><span style='color: white;'>L</span> <span style='color: {color}'>{str(item['low'])}</span><br><span style='color: white;'>C</span> <span style='color: {color}'>{str(item['close'])}</span><br><span style='color: dimgrey'>{formatted_date}</span>" + textHover.append(text) + fig = go.Figure(data=[ + go.Candlestick( + x=[item["date"] for item in dataChart], + open=[item['open'] for item in dataChart], + high=[item['high'] for item in dataChart], + low=[item['low'] for item in dataChart], + close=[item['close'] for item in dataChart], + text=textHover, + hoverinfo="text", + 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]) + ) + ) + + avWins, avLoss, vaWins, vaLoss = orders + print(avWins) + + for data, color, symbol, name, endName in [ + (avWins, 'green', 'triangle-up', 'AV Gains', 'Fin AV Gains'), + (avLoss, 'red', 'triangle-up', 'AV Pertes', 'Fin AV Pertes'), + (vaWins, 'green', 'triangle-down', 'VA Gains', 'Fin VA Gains'), + (vaLoss, 'red', 'triangle-down', 'VA Pertes', 'Fin VA Pertes') + ]: + fig.add_trace( + go.Scatter( + x=[order[0]['date'] for order in data], + y=[order[0]['price'] for order in data], + mode='markers', + name=name, + hoverinfo="name", + marker=dict( + symbol=symbol, + size=17, + color=color + ), + legendgroup=name + ) + ) + fig.add_trace( + go.Scatter( + showlegend=False, + x=[order[0]['timeExit'] for order in data], + y=[order[1] for order in data], + mode='markers', + name=endName, + hoverinfo="name", + marker=dict( + symbol='circle', + size=6, + color='black' + ), + legendgroup=name + ) + ) + + for data in [avWins, avLoss, vaWins, vaLoss]: + for order in data: + fig.add_trace( + go.Scatter( + x=[order[0]['date'], order[0]['timeExit']], + y=[order[0]['price'], order[1]], + mode='lines', + line=dict(color='black'), + hoverinfo="none", + showlegend=False, + legendgroup='AV Gains' if order in avWins else 'AV Pertes' if order in avLoss else 'VA Gains' if order in vaWins else 'VA Pertes' + ) + ) + fig.update_layout( + xaxis_rangeslider_visible=False, + title="Simulation sur le marché " + market, + xaxis_title="Date", + yaxis_title="Prix", + hovermode="closest", + 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() + figJson = json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder) + return figJson + + 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() layout = go.Layout( plot_bgcolor='#efefef', - # Font Families font_family='Monospace', font_color='#000000', font_size=20, @@ -232,7 +368,6 @@ def createFig(prices,orders,mas,periodes,market): df_order_av = df_order[df_order['type'] == 'AV'] df_order_va = df_order[df_order['type'] == 'VA'] - # put in rgbSMA array the rgb values for green and in other index the rgb values for light green rgbSMA = [[0,255,0], [0,200,0]] cpt = 0 for p in periodes: @@ -244,7 +379,6 @@ def createFig(prices,orders,mas,periodes,market): go.Scatter( x=df['date'], y=df['sma'], - #generate random color line=dict(color=f'rgb({rgbSMA[cpt][0]},{rgbSMA[cpt][1]},{rgbSMA[cpt][2]})', width=2), name='sma'+str(p) ) @@ -305,9 +439,6 @@ def getResults(): for j in dict['losses']: if i == j: dict['moneyLosses'][i] = dict['startBalance'][i] * (round(dict['losses'][j],2) * 0.01) - - print(dict['moneyProfits']) - print(dict['moneyLosses']) return dict diff --git a/main/simulation.py b/main/simulation.py index 25580c6c7dfb3ddebf814c08f4e835b336fa8f98..4100240d386f2e7ab5c89ed533250d44f4706867 100644 --- a/main/simulation.py +++ b/main/simulation.py @@ -43,6 +43,7 @@ from others.plotting_lib import plotCandles class Simulation: def __init__(self,sl,tp, market,base, target): self.strategie = "Doc simulus" + self.candle_prices = [] self.histo_prices= [] self.histo_candles= [] self.symbols = [] @@ -127,23 +128,28 @@ class Simulation: self.target = target self.market = market self.start_time =dt.now() + self.candle_prices = [] #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): random.seed(dt.now()) res=[] + resCandle = [] echant_x =[] - + cpt = 0 + tmpCandle = {} for i in range(1,int(periode_base/slices_sec)): echant_x.append(i*slices_sec) if format == True: candles = format_prices("simul") else: self.histo_candles = getHistoCandles(symbol,dateStart, dateEnd) + # print(self.histo_candles) candles = self.histo_candles pourcentage = settings.progressBar for c in candles: + Candles = {} xs=[] ys=[] # print(c) @@ -151,7 +157,9 @@ class Simulation: currentDate = dt.strptime(date,"%Y-%m-%d %H:%M:%S.%fZ") - + + + if format== False: date =self.formatDate(date) c = json.loads(c[0]) @@ -163,7 +171,6 @@ class Simulation: c = json.loads(c[0]) start = c["Open"] - tmpDateStart = dt.strptime(dateStart,"%Y-%m-%d %H:%M:%S.%fZ") tmpDateEnd = dt.strptime(dateEnd,"%Y-%m-%d %H:%M:%S.%fZ") totalDuration = (tmpDateEnd - tmpDateStart).total_seconds() @@ -172,10 +179,37 @@ class Simulation: settings.progressBar = pourcentage + (elapsedDuration / totalDuration) * (95-pourcentage) # print(percentage) #print(f"DATE Candle : {dt.fromtimestamp(date)}") - date = dt.fromtimestamp(date) - datetime.timedelta(0,periode_base) - #print(f"DATE calc : {date}") - + + if cpt == 0: + tmpCandle["open"] = c["Open"] + tmpCandle["date"] = str(date) + tmpCandle["high"] =c["High"] + tmpCandle["low"] =c["Low"] + elif cpt == 1: + if c["High"] > tmpCandle["high"]: + tmpCandle["high"] =c["High"] + if c["Low"] < tmpCandle["low"]: + tmpCandle["low"] =c["Low"] + elif cpt == 2: + if c["High"] > tmpCandle["high"]: + tmpCandle["high"] =c["High"] + if c["Low"] < tmpCandle["low"]: + tmpCandle["low"] =c["Low"] + tmpCandle["close"] =c["Close"] + Candles = tmpCandle + resCandle.append(Candles) + tmpCandle = {} + cpt = -1 + cpt += 1 + + # Candles["open"] = c["Open"] + # Candles["high"] = c["High"] + # Candles["low"] = c["Low"] + # Candles["close"] = c["Close"] + # Candles["date"] = str(date) + + # resCandle.append(Candles) res.append((start,str(date))) xs.append(0) @@ -194,9 +228,7 @@ class Simulation: ys.append(rand_2[0]) poly = lagrange(xs, ys) func = Polynomial(poly.coef[::-1]) - new_points = func(np.array(echant_x)) - - + new_points = func(np.array(echant_x)) for i,p in enumerate(new_points): #print(f"Old : {p}") @@ -213,6 +245,7 @@ class Simulation: self.plotPrice(res) # self.plotPrice(res) + self.candle_prices = resCandle self.histo_prices = res #print(self.histo_prices) @@ -429,6 +462,10 @@ class Simulation: m_between = self.minutesBetween(ord['date'],self.histo_prices[cpt][1]) #add h_between to order ord["duration"] = m_between + ord["timeExit"] = self.histo_prices[cpt][1] + + # print("WinsAV : ",ord, histo_price) + # print("Date fin ? ",self.histo_prices[cpt][1]) self.winsAV.append([ord,histo_price]) #print(f"Winning cycle AV => Price Enter : {ord['price']} & Price Exit : {histo_price} & TP : {self.tp*100}% ") cycle_ended = True @@ -437,6 +474,7 @@ class Simulation: m_between = self.minutesBetween(ord['date'],self.histo_prices[cpt][1]) #add h_between to order ord["duration"] = m_between + ord["timeExit"] = self.histo_prices[cpt][1] self.lossAV.append([ord,histo_price]) #print(f"Loosing cycle AV => Price Enter : {ord['price']} & Price Exit : {histo_price} & SL : {self.sl*100}%") cycle_ended = True @@ -445,6 +483,7 @@ class Simulation: if cycle_ended == False: m_between = self.minutesBetween(ord['date'],self.histo_prices[cpt][1]) ord["duration"] = m_between + ord["timeExit"] = self.histo_prices[cpt][1] self.end_forced_cycle.append([ord,histo_price]) #print(f"24h Limit Passed AV => Price Enter : {ord['price']} & Price Exit : {histo_price}") return cpt @@ -475,6 +514,7 @@ class Simulation: m_between = self.minutesBetween(ord['date'],self.histo_prices[cpt][1]) #add h_between to order ord["duration"] = m_between + ord["timeExit"] = self.histo_prices[cpt][1] self.winsVA.append([ord,histo_price]) cycle_ended = True #print(f"Winning cycle VA => Price Enter : {ord['price']} & Price Exit : {histo_price} & TP : {self.tp*100}%") @@ -484,6 +524,8 @@ class Simulation: m_between = self.minutesBetween(ord['date'],self.histo_prices[cpt][1]) #add h_between to order ord["duration"] = m_between + ord["timeExit"] = self.histo_prices[cpt][1] + self.lossVA.append([ord,histo_price]) cycle_ended = True #print(f"Loosing cycle VA => Price Enter : {ord['price']} & Price Exit : {histo_price} & SL : {self.sl*100}%") @@ -493,6 +535,7 @@ class Simulation: if cycle_ended == False: m_between = self.minutesBetween(ord['date'],self.histo_prices[cpt][1]) #add h_between to order + ord["timeExit"] = self.histo_prices[cpt][1] ord["duration"] = m_between self.end_forced_cycle.append([ord,histo_price]) #print(f"Time Limit Passed VA => Price Enter : {ord['price']} & Price Exit : {histo_price}") diff --git a/main/templates/.DS_Store b/main/templates/.DS_Store index ffeff0bdc683e3f91e60a808a2bb555ca0786833..52dae881498cdd08ea8924467dd64fec2fc48175 100644 Binary files a/main/templates/.DS_Store and b/main/templates/.DS_Store differ diff --git a/main/templates/index.html b/main/templates/index.html index c11c93227a3d03a8c336af19814fc057dcbf97ed..7b7cb19050b9b553f96884e4a66e4f41170e3d95 100644 --- a/main/templates/index.html +++ b/main/templates/index.html @@ -238,8 +238,7 @@ <div class="card shadow-2-strong card-registration" style="border-radius: 15px;"> <div class="card-body p-4"> <div class="row"> - <div id="chart"> - </div> + <div id="chart"></div> </div> <div class="row"> {% for symbol in res['profits'] %} @@ -384,9 +383,12 @@ </section> {% endif %} <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> -<script> +<script src="https://d3js.org/d3.v7.min.js"></script> +<script src="https://cdn.canvasjs.com/canvasjs.min.js"></script> +<script src="https://canvasjs.com/assets/script/jquery-1.11.1.min.js"></script> +<script> const showMoreInfo = document.getElementById('btnShowMoreInfo'); const indicatorSelect = document.getElementById('indicatorSelect'); @@ -397,8 +399,9 @@ var chart = null; {% if fig != None %} - var chart = {{ fig | safe }}; - Plotly.plot("chart", chart, {}); + chart = {{ fig | safe }}; + console.log(chart); + Plotly.plot("chart", chart, {}); {% endif %} if (!inProgress && chart == null) { diff --git a/main/templates/indexD3Chart.html b/main/templates/indexD3Chart.html new file mode 100644 index 0000000000000000000000000000000000000000..a033fdeaf4f3bf1465bd51642b527c8cd93ce484 --- /dev/null +++ b/main/templates/indexD3Chart.html @@ -0,0 +1,626 @@ +{% extends 'base.html' %} + +{% block content %} +{% if not inProgress and fig == None %} +<section class="gradient-custom p-5"> + <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"> + <div class="card shadow-2-strong card-registration" style="border-radius: 15px;"> + <div class="card-body p-4 p-md-5"> + <h3 class="mb-4 pb-2 pb-md-0 mb-md-2">Création d'une simulation</h3> + <form action="startSimulation" method="post"> + <div class="row"> + <div class="col-md-6 mb-4"> + <div class="form-outline"> + <label class="form-label" for="takeProfit">Take profit %</label> + <input type="number" + class="form-control form-control-lg {{ err['takeProfit'] }}" id="takeProfit" + name="takeProfit" max="100.0" min="1.0" + value="{{ stickyForm['takeProfit'] }}" step="0.1" required> + <div class="valid-feedback"> + Correct ! + </div> + <div class="invalid-feedback"> + Veuillez entrer un nombre entre 1.0 et 100.0 + </div> + </div> + + </div> + <div class="col-md-6 mb-4"> + + <div class="form-outline"> + <label class="form-label" for="stopLoss">Stop Loss %</label> + <input type="number" class="form-control form-control-lg {{ err['stopLoss'] }}" + id="stopLoss" name="stopLoss" min="1.0" max="100.0" + value="{{ stickyForm['stopLoss'] }}" step="0.1" required> + <div class="valid-feedback"> + Correct ! + </div> + <div class="invalid-feedback"> + Veuillez entrer un nombre entre 1 et 100.0 + </div> + </div> + + </div> + + </div> + + <div class="row"> + <div class="col-md-6 mb-4 d-flex align-items-center"> + + <div class="form-outline datepicker w-100"> + <label for="dateSimStart" class="form-label">Date du début de la + simulation</label> + <input type="date" class="form-control form-control-lg {{ err['dateSim'] }}" + id="dateSimStart" name="dateSimStart" + value="{{ stickyForm['dateSimStart'] }}" min="2022-02-05" max="2022-04-09" + required> + <div class="valid-feedback"> + Correct ! + </div> + <div class="invalid-feedback"> + Veuillez entrer une date entre le 05/02/2022 et le 09/04/2022. La date du + début ne doit pas être plus grande que la date de la fin ou égale. + </div> + </div> + + </div> + <div class="col-md-6 mb-4"> + + <div class="form-outline datepicker w-100"> + <label for="dateSimEnd" class="form-label">Date de la fin de la + simulation</label> + <input type="date" class="form-control form-control-lg {{ err['dateSim'] }}" + id="dateSimEnd" name="dateSimEnd" value="{{ stickyForm['dateSimEnd'] }}" + min="2022-02-05" max="2022-04-09" required> + <div class="valid-feedback"> + Correct ! + </div> + <div class="invalid-feedback"> + Veuillez entrer une date entre le 05/02/2022 et le 09/04/2022. La date de la + fin ne doit pas être plus petite que la date du début ou égale. + </div> + + </div> + </div> + </div> + <div class="row"> + <!-- <div class="col-md-6 mb-4 pb-2"> + + <div class="form-outline"> + <label class="form-label" for="candleSize">Taille de la bougie</label> + <input type="number" class="form-control form-control-lg" id="candleSize" + name="candleSize" max="20" min="5" value="10" step="1"> + </div> + + </div> --> + <div class="mb-4 pb-2"> + + <div class="form-inline"> + <label class="form-label my-1 mr-2" for="indicator">Indicateur + technique</label> + <select class="form-control form-select {{ err['indicator'] }}" + name="indicatorSelect" id="indicatorSelect" required> + {% if stickyForm['indicatorSelect'] == '' %} + <option value="" selected disabled hidden>Sélectionner...</option> + {% endif %} + {% if stickyForm['indicatorSelect'] == 'SMA' %} + <option value="SMA" selected>Moyenne glissante</option> + {% else %} + <option value="SMA">Moyenne glissante</option> + {% endif %} + {% if stickyForm['indicatorSelect'] == 'random'%} + <option value="random" selected>Aléatoire</option> + {% else %} + <option value="random">Aléatoire</option> + {% endif %} + {% if stickyForm['indicatorSelect'] == 'test' %} + <option value="test" selected>test</option> + {% else %} + <option value="test">test</option> + {% endif %} + </select> + <div class="valid-feedback"> + Correct ! + </div> + <div class="invalid-feedback"> + Veuillez sélectionner un indicateur de la liste. + </div> + </div> + + </div> + </div> + + <div class="row" id="rowSMA" style="display: none;"> + <div class="col-md-6 mb-4"> + <div class="form-outline"> + <label class="form-label" for="MA1">Moyenne glissante courte</label> + <input type="number" class="form-control form-control-lg {{ err['ma'] }}" + id="MA1" name="MA1" max="100" min="5" value="{{ stickyForm['MA1'] }}" + step="5"> + <div class="valid-feedback"> + Correct ! + </div> + <div class="invalid-feedback"> + Veuillez entrer un nombre entre 5 et 100. La moyenne glissante courte + doit être plus petite que la longue. + </div> + </div> + </div> + <div class="col-md-6 mb-4"> + <div class="form-outline"> + <label class="form-label" for="MA2">Moyenne glissante longue</label> + <input type="number" class="form-control form-control-lg {{ err['ma'] }}" + id="MA2" name="MA2" max="105" min="10" value="{{ stickyForm['MA2'] }}" + step="5"> + <div class="valid-feedback"> + Correct ! + </div> + <div class="invalid-feedback"> + Veuillez entrer un nombre entre 10 et 105. La moyenne glissante + longue doit être plus grande que la courte. + </div> + </div> + </div> + </div> + <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"> + </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"> + </div> + + </div> + </div> + <div class="row" id="rowTest" style="display: none;"> + <div class="col-md-6 mb-4"> + <div class="form-outline"> + <label class="form-label" for="M">Test 1</label> + <input type="number" class="form-control form-control-lg" id="MA1" name="MA1" + max="100" min="5" value="20" step="5"> + </div> + + </div> + <div class="col-md-6 mb-4"> + <label class="form-label" for="M">Test 2</label> + <div class="form-check form-switch"> + <input class="form-check-input" type="checkbox" id="flexSwitchCheckDefault"> + <label class="form-check-label" for="flexSwitchCheckDefault">Test</label> + </div> + + </div> + </div> + <div class="row text-center"> + <div class="mt-4 pt-2"> + <button type="submit" class="btn btn-primary btn-lg">Lancer la simulation</button> + </div> + </div> + </form> + </div> + </div> + </div> + </div> + </div> +</section> +{% endif %} +{% if inProgress %} +<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"> + <div class="card shadow-2-strong card-registration" style="border-radius: 15px;"> + <div class="card-body p-4 p-md-5"> + <div class="progress"> + <div class="progress-bar" id="progressBar" role="progressbar" aria-valuenow="0" + aria-valuemin="0" aria-valuemax="100" style="width:0%"></div> + </div> + </div> + </div> + </div> + </div> + </div> +</section> +{% endif %} +{% if fig != None %} +{% set moneySymbol = [] %} +<section class="gradient-custom p-5 h-100 align-items-center my-auto"> + <div class="container py-5 h-100"> + <div class="card shadow-2-strong card-registration" style="border-radius: 15px;"> + <div class="card-body p-4"> + <div class="row"> + <div id="candleChart"></div> + <div id="tooltip" style="position: absolute; opacity: 0;"></div> + </div> + <div class="row"> + {% for symbol in res['profits'] %} + {% set _ = moneySymbol.append(symbol) %} + <div class="col-md-6 mb-4 text-center"> + {% if symbol == "USDT" %} + <h1>{{ symbol }} : <span style="color:green"> +{{ res['moneyProfits'][symbol]|round(2)|string + }}₮ ({{ + res['profits'][symbol]|round(2)|string+"%" }})</span></h1> + {% elif symbol == "BTC" %} + <h1>{{ symbol }} : <span style="color:green"> +{{ + "{:.5f}".format(res['moneyProfits'][symbol])|string }}₿ ({{ + res['profits'][symbol]|round(2)|string+"%" }})</span></h1> + {% endif %} + </div> + {% endfor %} + {% for symbol in res['losses'] %} + {% set _ = moneySymbol.append(symbol) %} + <div class="col-md-6 mb-4 text-center"> + {% if symbol == "USDT" %} + <h1>{{ symbol }} : <span style="color:red">{{ res['moneyLosses'][symbol]|round(2)|string }}₮ ({{ + res['losses'][symbol]|round(2)|string+"%" }})</span></h1> + {% elif symbol == "BTC" %} + <h1>{{ symbol }} : <span style="color:red">{{ "{:.5f}".format(res['moneyLosses'][symbol])|string + }}₿ ({{ + res['losses'][symbol]|round(2)|string+"%" }})</span></h1> + {% endif %} + </div> + {% endfor %} + {% if res['profits'] == {} and res['losses'] == {} %} + <div class="text-center"> + <h1>Aucun résultats</h1> + <br> + </div> + {% endif %} + </div> + <div class="row align-items-center"> + <div class="col-sm mb-4 text-center"> + <button type="button" class="btn btn-secondary btn-lg" id="btnShowMoreInfo">Afficher plus de + 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"> + <div class="modal-header"> + <h5 class="modal-title">Nouvelle simulation</h5> + <button type="button" class="btn-close" data-bs-dismiss="modal" + aria-label="Fermer"></button> + </div> + <div class="modal-body"> + <div class="row"> + <div class="col-sm mb-4 text-center"> + <a href="resetSimulation"> + <button type="button" class="btn btn-primary btn-lg">Restaurer les + valeurs par défaut</button></a> + <br> + <br> + <a href="resetSimulationWithParams"> + <button type="button" class="btn btn-primary btn-lg">Modifier les + anciennes valeurs</button></a> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" + data-bs-dismiss="modal">Fermer</button> + </div> + </div> + </div> + </div> + </div> + <div class="col-sm mb-4 text-center"> + <button type="button" class="btn btn-success btn-lg"> + Enregistrer la simulation <i class="bi bi-save"></i> + </button> + </div> + </div> + <div id="moreResults" style="display: none;"> + <div class="row pt-3 mb-3 border-top"> + <div class="col-sm text-center"> + <h4>Balance avant</h4> + </div> + {% for i in moneySymbol %} + <div class="col-sm text-center"> + {% if i == "USDT" %} + <h4>{{ res['startBalance'][i] }}₮</h4> + {% elif i == "BTC" %} + <h4>{{res['startBalance'][i] }}₿ </h4> + {% endif %} + </div> + {% endfor %} + </div> + <div class="row pt-3 mb-3 border-top"> + <div class="col-sm text-center"> + <h4>Balance après</h4> + </div> + {% for i in res['profits'] %} + <div class="col-sm text-center"> + {% if i == "USDT" %} + <h4>{{ res['startBalance'][i] + res['moneyProfits'][i]}}₮</h4> + {% elif i == "BTC" %} + <h4>{{"{:.5f}".format(res['startBalance'][i] + res['moneyProfits'][i])}}₿ </h4> + {% endif %} + </div> + {% endfor %} + {% for i in res['losses'] %} + <div class="col-sm text-center"> + {% if i == "USDT" %} + <h4>{{ res['startBalance'][i] + res['moneyLosses'][i]}}₮</h4> + {% elif i == "BTC" %} + <h4>{{"{:.5f}".format(res['startBalance'][i] + res['moneyLosses'][i])}}₿ </h4> + {% endif %} + </div> + {% endfor %} + </div> + <div class="row pt-3 mb-3 border-top"> + <div class="col-sm text-center"> + <h5>Nombre d'ordres gagants : {{ res['nbWins'] }}</h5> + </div> + <div class="col-sm text-center"> + <h5>Nombre d'ordres perdants : {{ res['nbLosses'] }}</h5> + </div> + <div class="col-sm text-center"> + <h5>Nombre total d'ordres : {{ res['totalTrades'] }}</h5> + </div> + <div class="col-sm text-center"> + <h5>Pourcentage de réussite : {{ res['winrate'] }}%</h5> + </div> + </div> + </div> + </div> + </div> + </div> +</section> +{% endif %} +<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> +<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> +<script src="https://www.chartjs.org/chartjs-chart-financial/chartjs-chart-financial.js"></script> +<script src="https://cdn.jsdelivr.net/npm/luxon@1.26.0"></script> +<script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.1/dist/chart.js"></script> +<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.0.0"></script> +<script src="https://www.chartjs.org/chartjs-chart-financial/chartjs-chart-financial.js"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script> +<script src="https://d3js.org/d3.v7.min.js"></script> +{% if fig != None %} +<script> + function getRandomArbitrary(min, max) { + return Math.random() * (max - min) + min; + } + + var data = {{ fig | safe }} + console.log(data) + var baseValue = 100; + var baseDate = new Date(data[0].date); + + console.log(data.length) + data.forEach(function (d) { + d.date = new Date(d.date); + }); + + + var margin = { top: 20, right: 50, bottom: 30, left: 50 }, + width = 960 - margin.left - margin.right, + height = 500 - margin.top - margin.bottom; + var barWidth = Math.floor(width / data.length); + + var x = d3.scaleTime() + .domain(d3.extent(data, d => d.date)) + .range([0, width]); + + var y = d3.scaleLinear() + .domain([d3.min(data, d => d.low), d3.max(data, d => d.high)]) + .range([height, 0]); + + var svg = d3.select("#candleChart").append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + svg.append("rect") + .attr("width", width) + .attr("height", height) + .style("fill", "none") + .style("pointer-events", "all"); + + + var barWidth = Math.floor(width / data.length); + + var xAxis = d3.axisBottom(x); + + var yAxis = d3.axisLeft(y); + + // Ajouter les axes au SVG + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + height + ")") + .call(xAxis); + + svg.append("g") + .attr("class", "y axis") + .call(yAxis); + + // Définir la fonction de zoom + //var barWidth = 15; // Largeur des bougies en pixels + + var zoom = d3.zoom() + .scaleExtent([1, 100]) // Zoom limité entre 1x et 100x + .extent([[0, 0], [width, height]]) + .on("zoom", function (event) { + // Mettre à jour les échelles + var new_xScale = event.transform.rescaleX(x); + + // Calculer la nouvelle largeur des bougies + var t = event.transform, + xt = t.rescaleX(x); + + // Si le zoom est au maximum + if (t.k === 100) { // 100 est le niveau de zoom maximum défini par scaleExtent([1, 100]) + var firstDate = data[0].date; + var lastDate = new Date(firstDate.getTime() + 15 * 60 * 1000); // 15 minutes plus tard + xt.domain([firstDate, lastDate]); + } + + barWidth = Math.max(1, Math.min(barWidth, width / xt.domain().length)); + + // Mettre à jour les bougies et les tiges + svg.selectAll("rect.candle") + .attr("x", d => xt(d.date) - 0.5 * barWidth) + .attr("width", barWidth); + svg.selectAll("line.stem") + .attr("x1", d => xt(d.date)) + .attr("x2", d => xt(d.date)); + + // Appeler les axes sur leurs sélections respectives + svg.select(".x.axis").call(xAxis.scale(new_xScale)); + svg.select(".y.axis").call(yAxis); + }); + + + function zoomed({ transform }) { + svg.attr("transform", transform); + } + + svg.call(zoom); + + svg.selectAll("line.stem") + .data(data) + .enter().append("line") + .attr("class", "stem") + .attr("x1", d => x(d.date)) + .attr("x2", d => x(d.date)) + .attr("y1", d => y(d.high)) + .attr("y2", d => y(d.low)) + .attr("stroke", d => d.open === d.close ? "darkgrey" : d.open > d.close ? "red" : "green"); + + svg.selectAll("rect.candle") + .data(data) + .enter().append("rect") + .attr("class", "candle") + .attr("x", d => x(d.date) - 0.5 * barWidth) + .attr("y", d => y(Math.max(d.open, d.close))) + .attr("width", barWidth) + .attr("height", d => y(Math.min(d.open, d.close)) - y(Math.max(d.open, d.close))) + .attr("fill", d => d.open === d.close ? "darkgrey" : d.open > d.close ? "red" : "green"); + + + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + height + ")") + .call(d3.axisBottom(x)); + + svg.append("g") + .attr("class", "y axis") + .call(d3.axisLeft(y)); + + + // Ajouter un événement mouseover à chaque bougie + svg.selectAll("rect.candle") + .on("mouseover", function (event, d) { + // Changer l'opacité de l'infobulle + d3.select("#tooltip").style("opacity", 1); + + // Changer le texte de l'infobulle + d3.select("#tooltip").html( + "Date: " + d.date.toISOString() + "<br/>" + + "Open: " + d.open.toFixed(2) + "<br/>" + + "Close: " + d.close.toFixed(2) + "<br/>" + + "High: " + d.high.toFixed(2) + "<br/>" + + "Low: " + d.low.toFixed(2) + ) + }) + .on("mousemove", function (event, d) { + // Déplacer l'infobulle + d3.select("#tooltip") + .style("left", (event.pageX + 10) + "px") + .style("top", (event.pageY - 10) + "px"); + }) + .on("mouseout", function (event, d) { + // Cacher l'infobulle + d3.select("#tooltip").style("opacity", 0); + }); + +</script> +{% endif %} + +<script> + const showMoreInfo = document.getElementById('btnShowMoreInfo'); + + const indicatorSelect = document.getElementById('indicatorSelect'); + const SMA = document.getElementById('rowSMA'); + const random = document.getElementById('rowRandom'); + const test = document.getElementById('rowTest'); + var inProgress = {{ inProgress| lower }}; + var chart = null; + //var chartData = {{ fig | safe }}; + + {% if fig != None %} + chart = {{ fig | safe }}; + //var chart = {{ fig | safe }}; + //Plotly.plot("chart", chart, {}); + {% endif %} + + if (!inProgress && chart == null) { + indicatorChange(); + indicatorSelect.addEventListener('change', indicatorChange); + } + if (inProgress) { + updateProgressBar(); + } + + + {% if fig != None %} + 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'; + } + }); + {% endif %} + + function updateProgressBar() { + $.ajax({ + url: '/progress', + success: function (data) { + var progress = data.progress; + $('#progressBar').css('width', progress + '%'); + if (progress === 100) { + location.reload(); + } else { + setTimeout(updateProgressBar, 1000); + } + } + }); + } + + function indicatorChange() { + if (indicatorSelect.value === 'SMA') { + SMA.style.display = 'flex'; + random.style.display = 'none'; + test.style.display = 'none'; + } else if (indicatorSelect.value === 'random') { + random.style.display = 'flex'; + SMA.style.display = 'none'; + test.style.display = 'none'; + } else if (indicatorSelect.value === 'test') { + test.style.display = 'flex'; + SMA.style.display = 'none'; + random.style.display = 'none'; + } + } +</script> +{% endblock %} \ No newline at end of file