Skip to content

Commit bcae37c

Browse files
committed
Add line between trade arrows !
1 parent 9994739 commit bcae37c

File tree

2 files changed

+109
-24
lines changed

2 files changed

+109
-24
lines changed

Controller.py

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from CerebroEnhanced import *
2626

2727
import sys, os
28+
from backtrader.order import BuyOrder, SellOrder
2829
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/observers')
2930
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/strategies')
3031
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + '/../finplot')
@@ -67,13 +68,10 @@ def __init__(self):
6768

6869
# Add an observer to watch the strat running and update the progress bar values
6970
self.cerebro.addobserver( ProgressBarObserver )
70-
7171
pass
7272

7373
def loadData(self, dataPath):
7474

75-
#self.dataframe = pandas.read_csv(dataPath,sep='\t',skiprows=0,header=0,index_col=0)
76-
7775
self.dataframe = pd.read_csv(dataPath, sep='\t', parse_dates=[0], date_parser=lambda x: pd.to_datetime(x, format='%Y-%m-%d %H:%M:%S'),skiprows=0,header=0,index_col=0)
7876

7977
# Datetime first column : 2012-12-28 17:45:00
@@ -83,6 +81,7 @@ def loadData(self, dataPath):
8381
self.data = bt.feeds.PandasData(dataname=self.dataframe, timeframe=bt.TimeFrame.Minutes)
8482

8583
self.cerebro.adddata(self.data) # Add the data feed
84+
pass
8685

8786
def addStrategy(self, strategyName):
8887

@@ -92,13 +91,14 @@ def addStrategy(self, strategyName):
9291
mod = __import__(strategyName, fromlist=[strategyName]) # first strategyName is the file name, and second (fromlist) is the class name
9392
klass = getattr(mod, strategyName) # class name in the file
9493
self.cerebro.addstrategy(klass)
94+
pass
9595

9696
def run(self):
9797
results = self.cerebro.run() # run it all
9898
self.strat_results = results[0] # results of the first strategy
9999

100-
self.populateOrders()
101100
self.generateStats()
101+
pass
102102

103103
def generateStats(self):
104104
# Stats on trades
@@ -109,32 +109,25 @@ def generateStats(self):
109109

110110
#self.interface.createTransactionsUI(self.portfolio_transactions)
111111

112-
self.interface.fillTradesUI(self.strat_results._trades.items())
113-
self.interface.fillSummaryUI(self.strat_results.stats.broker.cash[0], self.strat_results.stats.broker.value[0], self.strat_results.analyzers.ta.get_analysis())
114-
115112
self.interface.drawFinPlots(self.dataframe)
116-
117-
# Orders need to be stuied to know if an order is an open or a close order, or both...
118-
# It depends on the order volume and the currently opened positions volume
119-
self.interface.drawOrders(self.myOrders)
120-
121-
pass
122-
123-
def populateOrders(self): # todo : rename this functions later
113+
self.interface.fillSummaryUI(self.strat_results.stats.broker.cash[0], self.strat_results.stats.broker.value[0], self.strat_results.analyzers.ta.get_analysis())
114+
self.interface.fillTradesUI(self.strat_results._trades.items())
115+
116+
#self.interface.drawTrades(self.strat_results._trades.items())
124117
#Orders filters
125118
self.myOrders = []
126119
for order in self.strat_results._orders:
127120

128121
if order.status in [order.Completed]:
129122
self.myOrders.append(order)
130123

131-
132-
133-
134124
self.interface.fillOrdersUI(self.myOrders)
125+
self.interface.drawOrders(self.myOrders)
135126

136127
pass
128+
137129

138130
def displayUI(self):
139131

140-
self.interface.show()
132+
self.interface.show()
133+
pass

userInterface.py

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import strategyTesterUI
3030

3131
import pandas as pd
32+
import math
3233

3334
class UserInterface:
3435

@@ -263,10 +264,12 @@ def update_legend_text(self, x, y, ax, data):
263264
row = data.loc[data.TimeInt==x]
264265

265266
# format html with the candle and set legend
266-
fmt = '<span style="color:#%s">%%.2f</span>' % ('0b0' if (row.Open<row.Close).all() else 'a00')
267+
fmt = '<span style="color:#%s">%%.5f</span>' % ('0f0' if (row.Open<row.Close).all() else 'd00')
267268
rawtxt = '<span style="font-size:13px">%%s %%s</span> &nbsp; O%s C%s H%s L%s' % (fmt, fmt, fmt, fmt)
268269
self.hover_label.setText(rawtxt % ("EUR", "M15", row.Open, row.Close, row.High, row.Low))
269270

271+
pass
272+
270273
def update_crosshair_text(self,x, y, xtext, ytext):
271274
ytext = '%s (Close%+.2f)' % (ytext, (y - self.data.iloc[x].Close))
272275
return xtext, ytext
@@ -282,7 +285,6 @@ def drawFinPlots(self, data):
282285
self.ax0, self.ax1 = fplt.create_plot_widget(master=self.area, rows=2, init_zoom_periods=100)
283286
self.area.axs = [self.ax0, self.ax1]
284287
self.dock_chart.addWidget(self.ax0.ax_widget, 1, 0, 1, 2)
285-
#self.dock_1.addWidget(ax1.ax_widget, 1, 0, 1, 2)
286288

287289
fplt.candlestick_ochl(data['Open Close High Low'.split()], ax=self.ax0)
288290
fplt.volume_ocv(data['Open Close Volume'.split()], ax=self.ax0.overlay())
@@ -291,23 +293,112 @@ def drawFinPlots(self, data):
291293
fplt.set_time_inspector(self.update_legend_text, ax=self.ax0, when='hover', data=data)
292294
#fplt.add_crosshair_info(self.update_crosshair_text, ax=self.ax0)
293295

294-
# def add_line(p0, p1, color=draw_line_color, width=1, style=None, interactive=False, ax=None):
295-
#fplt.add_line();
296+
pass
296297

297298
#########
298299
# Draw orders on charts (with arrows)
299300
#########
300301
def drawOrders(self, orders):
301302

303+
# Orders need to be stuied to know if an order is an open or a close order, or both...
304+
# It depends on the order volume and the currently opened positions volume
305+
currentPositionSize = 0
306+
open_orders = []
307+
302308
for order in orders:
309+
310+
##############
311+
# Buy
312+
##############
303313
if order.isbuy():
314+
304315
direction = "buy"
316+
317+
# Tracer les traites allant des ouvertures de positions vers la fermeture de position
318+
if currentPositionSize < 0:
319+
320+
# Réduction, cloture, ou invertion de la position
321+
if order.size == abs(currentPositionSize): # it's a buy so order.size > 0
322+
# Cloture de la position
323+
posOpen = (open_orders[-1].executed.dt,open_orders[-1].executed.price)
324+
posClose = (bt.num2date(order.executed.dt), order.executed.price)
325+
fplt.add_line(posOpen, posClose, "#30FF30", 2, style="--" )
326+
pass
327+
328+
elif order.size > abs(currentPositionSize):
329+
# Fermeture de la position précédente + ouverture d'une position inverse
330+
pass
331+
332+
elif order.size < abs(currentPositionSize):
333+
# Réduction de la position courante
334+
pass
335+
336+
elif currentPositionSize > 0:
337+
# Augmentation de la postion
338+
# on enregistre la position pour pouvoir tracer un trait de ce point vers l'ordre de cloture du trade.
339+
open_orders.append(order)
340+
341+
else:
342+
# Ouverture d'une nouvelle position
343+
open_orders.append(order)
344+
pass
345+
346+
##############
347+
# Sell
348+
##############
305349
elif order.issell():
306350
direction = "sell"
307-
351+
352+
353+
if currentPositionSize < 0:
354+
# Augmentation de la postion
355+
356+
# on enregistre la position pour pouvoir tracer un trait de ce point vers l'ordre de cloture du trade.
357+
open_orders.append(order)
358+
359+
elif currentPositionSize > 0:
360+
# Réduction, cloture, ou invertion de la position
361+
362+
if abs(order.size) == abs(currentPositionSize): # it's a buy so order.size > 0
363+
# Cloture de la position
364+
last_order = open_orders.pop()
365+
posOpen = (bt.num2date(last_order.executed.dt),last_order.executed.price)
366+
posClose = (bt.num2date(order.executed.dt), order.executed.price)
367+
368+
color = "#555555"
369+
if order.executed.pnl > 0:
370+
color = "#30FF30"
371+
elif order.executed.pnl < 0:
372+
color = "#FF3030"
373+
374+
fplt.add_line(posOpen, posClose, color, 2, style="--" )
375+
376+
pass
377+
378+
elif order.size > abs(currentPositionSize):
379+
# Réduction de la position courante
380+
pass
381+
382+
elif order.size < abs(currentPositionSize):
383+
# Fermeture de la position précédente + ouverture d'une position inverse
384+
pass
385+
386+
else:
387+
# Ouverture d'une nouvelle position
388+
open_orders.append(order)
389+
pass
390+
391+
else:
392+
print("Unknown order")
393+
394+
# Cumul des positions
395+
currentPositionSize += order.size
396+
397+
# Todo: We could display the size of the order with a label on the chart
308398
fplt.add_order(bt.num2date(order.executed.dt), order.executed.price, direction, ax=self.ax0)
309399

310400
pass
401+
311402

312403
#########
313404
# Show all
@@ -318,6 +409,7 @@ def show(self):
318409

319410
self.win.show()
320411
self.app.exec_()
412+
pass
321413

322414
#########
323415
# Get strategy running progress bar

0 commit comments

Comments
 (0)