Skip to content

Commit 8dae422

Browse files
committed
Add dock widget indicators
Add Dock widget for indicators
1 parent 09dedf0 commit 8dae422

File tree

5 files changed

+194
-15
lines changed

5 files changed

+194
-15
lines changed

common.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env python3
2+
3+
from math import nan
4+
5+
def calc_parabolic_sar(df, af=0.2, steps=10):
6+
up = True
7+
sars = [nan] * len(df)
8+
sar = ep_lo = df.Low.iloc[0]
9+
ep = ep_hi = df.High.iloc[0]
10+
aaf = af
11+
aaf_step = aaf / steps
12+
af = 0
13+
for i,(hi,lo) in enumerate(zip(df.High, df.Low)):
14+
# parabolic sar formula:
15+
sar = sar + af * (ep - sar)
16+
# handle new extreme points
17+
if hi > ep_hi:
18+
ep_hi = hi
19+
if up:
20+
ep = ep_hi
21+
af = min(aaf, af+aaf_step)
22+
elif lo < ep_lo:
23+
ep_lo = lo
24+
if not up:
25+
ep = ep_lo
26+
af = min(aaf, af+aaf_step)
27+
# handle switch
28+
if up:
29+
if lo < sar:
30+
up = not up
31+
sar = ep_hi
32+
ep = ep_lo = lo
33+
af = 0
34+
else:
35+
if hi > sar:
36+
up = not up
37+
sar = ep_lo
38+
ep = ep_hi = hi
39+
af = 0
40+
sars[i] = sar
41+
df['sar'] = sars
42+
return df['sar']
43+
44+
45+
def calc_rsi(df, n=14):
46+
diff = df.Close.diff().values
47+
gains = diff
48+
losses = -diff
49+
gains[~(gains>0)] = 0.0
50+
losses[~(losses>0)] = 1e-10 # we don't want divide by zero/NaN
51+
m = (n-1) / n
52+
ni = 1 / n
53+
g = gains[n] = gains[:n].mean()
54+
l = losses[n] = losses[:n].mean()
55+
gains[:n] = losses[:n] = nan
56+
for i,v in enumerate(gains[n:],n):
57+
g = gains[i] = ni*v + m*g
58+
for i,v in enumerate(losses[n:],n):
59+
l = losses[i] = ni*v + m*l
60+
rs = gains / losses
61+
rsi = 100 - (100/(1+rs))
62+
return rsi
63+
64+
65+
def calc_stochastic_oscillator(df, n=14, m=3, smooth=3):
66+
lo = df.Low.rolling(n).min()
67+
hi = df.High.rolling(n).max()
68+
k = 100 * (df.Close-lo) / (hi-lo)
69+
d = k.rolling(m).mean()
70+
return k, d
71+

finplotWindow.py

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from pyqtgraph.graphicsItems.LegendItem import LegendItem
44

55
from indicators import ichimoku
6+
from indicators import rsi
67

78
sys.path.append('../finplot')
89
import finplot as fplt
@@ -19,9 +20,9 @@ def __init__(self, dockArea, dockChart, interface):
1920
self.interface = interface
2021

2122
self.IndIchimokuActivated = False
22-
self.IndRSIActivated = False
23+
self.IndRsiActivated = False
2324
self.IndStochasticActivated = False
24-
self.IndMAActivated = False
25+
self.IndStochasticRsiActivated = False
2526

2627
self.IndVolumesActivated = False
2728

@@ -33,17 +34,25 @@ def __init__(self, dockArea, dockChart, interface):
3334
def createPlotWidgets(self):
3435

3536
# fin plot
36-
self.ax0, self.ax1, self.ax2, self.axPnL = fplt.create_plot_widget(master=self.dockArea, rows=4, init_zoom_periods=200)
37-
self.dockArea.axs = [self.ax0, self.ax1, self.ax2, self.axPnL]
37+
self.ax0, self.ax_rsi, self.ax_stochasticRsi, self.ax_stochastic, self.axPnL = fplt.create_plot_widget(master=self.dockArea, rows=5, init_zoom_periods=200)
38+
self.dockArea.axs = [self.ax0] # , self.ax_rsi, self.ax2, self.axPnL
3839
self.dockChart.addWidget(self.ax0.ax_widget, 1, 0, 1, 1)
39-
self.dockChart.addWidget(self.ax1.ax_widget, 2, 0, 1, 1)
40+
41+
'''
42+
self.dockChart.addWidget(self.ax_rsi.ax_widget, 2, 0, 1, 1)
4043
self.dockChart.addWidget(self.ax2.ax_widget, 3, 0, 1, 1)
44+
'''
45+
46+
self.interface.dock_rsi.layout.addWidget(self.ax_rsi.ax_widget)
47+
self.interface.dock_stochasticRsi.layout.addWidget(self.ax_stochasticRsi.ax_widget)
48+
self.interface.dock_stochastic.layout.addWidget(self.ax_stochastic.ax_widget)
4149

50+
# Ax Profit & Loss
4251
self.interface.strategyResultsUI.ResultsTabWidget.widget(1).layout().addWidget(self.axPnL.ax_widget)
43-
#self.dockChart.addWidget(self.axPnL.ax_widget, 4, 0, 1, 1)
4452

45-
self.ax1.ax_widget.hide()
46-
self.ax2.ax_widget.hide()
53+
self.ax_rsi.ax_widget.hide()
54+
self.ax_stochasticRsi.ax_widget.hide()
55+
self.ax_stochastic.ax_widget.hide()
4756
self.axPnL.ax_widget.hide()
4857
pass
4958

@@ -319,15 +328,30 @@ def updateChart(self):
319328
self.ichimoku_indicator = ichimoku.Ichimoku(self.data)
320329
self.ichimoku_indicator.draw(self.ax0)
321330

331+
if self.IndRsiActivated:
332+
self.rsi_indicator = rsi.Rsi(self.data)
333+
self.rsi_indicator.draw(self.ax_rsi)
334+
self.ax_rsi.ax_widget.show()
335+
else:
336+
self.ax_rsi.ax_widget.hide()
337+
pass
338+
339+
if self.IndStochasticActivated:
340+
pass
341+
342+
if self.IndStochasticRsiActivated:
343+
pass
344+
345+
if self.IndVolumesActivated:
346+
fplt.volume_ocv(self.data['Open Close Volume'.split()], ax=self.ax0.overlay())
347+
348+
322349
# Finally draw candles
323350
self.drawCandles()
324351

325352
# Draw orders
326353
self.drawOrders()
327354

328-
if self.IndVolumesActivated:
329-
fplt.volume_ocv(self.data['Open Close Volume'.split()], ax=self.ax0.overlay())
330-
331355
# Refresh view : auto zoom
332356
fplt.refresh()
333357

@@ -336,6 +360,15 @@ def updateChart(self):
336360

337361
def setIndicator(self, indicatorName, activated):
338362

363+
if (indicatorName == "Rsi"):
364+
self.IndRsiActivated = activated
365+
366+
if (indicatorName == "Stochastic"):
367+
self.IndStochasticActivated = activated
368+
369+
if (indicatorName == "StochasticRsi"):
370+
self.IndStochasticRsiActivated = activated
371+
339372
if (indicatorName == "Ichimoku"):
340373
self.IndIchimokuActivated = activated
341374

indicators/ichimoku.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import backtrader as bt
1010
import backtrader.indicators as btind
1111

12+
1213
import pandas as pd
1314

1415
class Ichimoku():

indicators/rsi.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env python3
2+
import sys
3+
4+
sys.path.append('../finplot')
5+
import finplot as fplt
6+
7+
import backtrader.functions as func
8+
from pyqtgraph.functions import Color
9+
10+
from common import calc_rsi
11+
from common import calc_parabolic_sar
12+
from common import calc_stochastic_oscillator
13+
14+
class Rsi():
15+
16+
def __init__(self, dataFrames, rsi_periods=14):
17+
self.rsi_df = calc_rsi(dataFrames, rsi_periods)
18+
pass
19+
20+
def draw(self, ax, rsi_color = "magenta"):
21+
self.rsi_plot = fplt.plot(self.rsi_df, ax = ax, color=rsi_color, width=1 )
22+
pass
23+
24+
def clear(self):
25+
26+
pass

userInterface.py

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,19 @@ def createDocks(self):
9797
self.dockArea.addDock(self.dock_strategyResultsUI, position='bottom')
9898

9999
# Create Order widget
100-
#self.dock_orders = Dock("Orders", size = (1000, 200), closable = False)
101-
#self.dockArea.addDock(self.dock_orders, position='below', relativeTo=self.dock_trades)
100+
self.dock_rsi = Dock("RSI", size = (1000, 120), closable = False, hideTitle=True)
101+
self.dockArea.addDock(self.dock_rsi, position='bottom', relativeTo=self.dock_chart)
102+
self.dock_rsi.hide()
103+
104+
self.dock_stochastic = Dock("Stochastic", size = (1000, 120), closable = False, hideTitle=True)
105+
self.dockArea.addDock(self.dock_stochastic, position='bottom', relativeTo=self.dock_chart)
106+
self.dock_stochastic.hide()
107+
108+
self.dock_stochasticRsi = Dock("Stochastic Rsi", size = (1000, 120), closable = False, hideTitle=True)
109+
self.dockArea.addDock(self.dock_stochasticRsi, position='bottom', relativeTo=self.dock_chart)
110+
self.dock_stochasticRsi.hide()
111+
112+
102113
#self.dock_trades.raiseDock()
103114

104115
#########
@@ -478,6 +489,30 @@ def createControlPanel(self):
478489
self.ResetPB.toggled.connect(self.resetChart)
479490
layout.addWidget(self.ResetPB)
480491

492+
# RSI
493+
self.RsiPB = QtWidgets.QPushButton(self.panel)
494+
self.RsiPB.setText("RSI")
495+
self.RsiPB.setCheckable(True)
496+
self.RsiPB.setMaximumWidth(100)
497+
self.RsiPB.toggled.connect(self.addRsi)
498+
layout.addWidget(self.RsiPB)
499+
500+
# Stochastic
501+
self.StochasticPB = QtWidgets.QPushButton(self.panel)
502+
self.StochasticPB.setText("Stochastic")
503+
self.StochasticPB.setCheckable(True)
504+
self.StochasticPB.setMaximumWidth(100)
505+
self.StochasticPB.toggled.connect(self.addStochastic)
506+
layout.addWidget(self.StochasticPB)
507+
508+
# Stochastic RSI
509+
self.StochasticRsiPB = QtWidgets.QPushButton(self.panel)
510+
self.StochasticRsiPB.setText("Stochastic RSI")
511+
self.StochasticRsiPB.setCheckable(True)
512+
self.StochasticRsiPB.setMaximumWidth(100)
513+
self.StochasticRsiPB.toggled.connect(self.addStochasticRsi)
514+
layout.addWidget(self.StochasticRsiPB)
515+
481516
# Ichimoku
482517
self.IchimokuPB = QtWidgets.QPushButton(self.panel)
483518
self.IchimokuPB.setText("Ichimoku")
@@ -521,15 +556,28 @@ def resetChart(self):
521556
self.fpltWindow.updateChart()
522557
pass
523558

559+
def addRsi(self):
560+
self.fpltWindow.setIndicator("Rsi", self.RsiPB.isChecked() )
561+
self.dock_rsi.show() if self.RsiPB.isChecked() else self.dock_rsi.hide()
562+
pass
563+
564+
def addStochastic(self):
565+
self.fpltWindow.setIndicator("Stochastic", self.StochasticPB.isChecked() )
566+
self.dock_stochastic.show() if self.StochasticPB.isChecked() else self.dock_stochastic.hide()
567+
pass
568+
569+
def addStochasticRsi(self):
570+
self.fpltWindow.setIndicator("StochasticRsi", self.StochasticRsiPB.isChecked() )
571+
self.dock_stochasticRsi.show() if self.StochasticRsiPB.isChecked() else self.dock_stochasticRsi.hide()
572+
pass
573+
524574
def addIchimoku(self):
525575
self.fpltWindow.setIndicator("Ichimoku", self.IchimokuPB.isChecked() )
526576
pass
527577
def volumes_toggle(self):
528578
self.fpltWindow.setIndicator("Volumes", self.volumesCB.isChecked())
529579
pass
530580

531-
532-
533581
#########
534582
# Obsolete (Strategy results : transcations tab)
535583
#########

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy