Invicto69 commited on
Commit
7d8ad6e
·
verified ·
1 Parent(s): 92283e1

Upload 6 files

Browse files
Files changed (6) hide show
  1. app.py +148 -0
  2. data_fetcher.py +6 -0
  3. gradio_app.py +65 -0
  4. indicators.py +252 -0
  5. requirements.txt +8 -0
  6. strategies.py +108 -0
app.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import Dash, Input, Output, State, callback, dcc, html
2
+ import dash_bootstrap_components as dbc
3
+ import pandas as pd
4
+ from indicators import SMC
5
+ from data_fetcher import fetch
6
+ from strategies import smc_plot_backtest, smc_ema_plot_backtest
7
+
8
+ # Load symbols data
9
+ symbols = pd.read_csv('data/Ticker_List_NSE_India.csv')
10
+
11
+ # Initialize the app with a Bootstrap theme
12
+ app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
13
+
14
+ # Function to create the layout
15
+ app.layout = dbc.Container([
16
+ dbc.Row([
17
+ html.H1("Algorithmic Trading Dashboard", className="text-center mb-4")
18
+ ]),
19
+
20
+ dbc.Row([
21
+ html.Label("Select Company Name", className="form-label"),
22
+ dcc.Dropdown(
23
+ id="name",
24
+ options=[{"label": name, "value": name} for name in symbols['NAME OF COMPANY'].unique()],
25
+ value='',
26
+ placeholder="Select a company",
27
+ className="mb-3"
28
+ ),
29
+
30
+ html.Label("Select Strategy", className="form-label"),
31
+ dcc.Dropdown(
32
+ id="strategy",
33
+ options=['SMC', 'SMC with EMA'],
34
+ value='',
35
+ placeholder="Select Strategy",
36
+ className="mb-3"
37
+ ),
38
+
39
+ html.Label("Swing High/Low Window Size", className="form-label"),
40
+ dcc.Input(
41
+ id="window",
42
+ type="number",
43
+ value=10,
44
+ placeholder="Enter window size",
45
+ className="form-control mb-3"
46
+ ),
47
+
48
+ ]),
49
+
50
+ html.Div([
51
+ dbc.Row([
52
+ dbc.Col([
53
+ html.Label("Fast EMA Length: ", className="form-label"),
54
+ dcc.Input(
55
+ id="ema1",
56
+ type="number",
57
+ value=9,
58
+ placeholder="Enter EMA Length",
59
+ # className="form-control mb-3"
60
+ className = "text-nowrap"
61
+ ),
62
+ ], md=8),
63
+
64
+ dbc.Col([
65
+ html.Label("Slow EMA Length: ", className="form-label"),
66
+ dcc.Input(
67
+ id="ema2",
68
+ type="number",
69
+ value=21,
70
+ placeholder="Enter EMA size",
71
+ # className="form-control mb-3"
72
+ className="text-nowrap"
73
+ ),
74
+
75
+ dbc.Col([dcc.Checklist(['Close on EMA crossover'], id='closecross', className="text-nowrap")]),
76
+
77
+ ]),
78
+ ]),
79
+ ], style={'display': 'block'}, id='smc_ema'
80
+ ),
81
+
82
+ dbc.Button("Run", id="submit-button", color="primary", className="w-100 mb-4"),
83
+
84
+ dbc.Row([
85
+ html.H5("Order Block Chart", className="text-center mb-3"),
86
+ html.Iframe(
87
+ src="assets/SMC.html",
88
+ style={"height": "450px", "width": "95%", "border": "none"},
89
+ className="mb-4"
90
+ ),
91
+
92
+ html.H5("Backtest Results", className="text-center mb-3"),
93
+ html.Iframe(
94
+ src="assets/backtest_results.html",
95
+ style={"height": "1067px", "width": "95%", "border": "none"}
96
+ ),
97
+ ])
98
+ ], fluid=True)
99
+
100
+
101
+ @callback(
102
+ Output("smc_ema", 'style'),
103
+ Input("strategy", 'value')
104
+ )
105
+ def update_layout(strategy):
106
+ if strategy=='SMC with EMA':
107
+ return {'display':'block'}
108
+ else:
109
+ return {'display':'none'}
110
+
111
+
112
+ # Callback for updating the visualizations
113
+ @callback(
114
+ Input("submit-button", "n_clicks"),
115
+ State("name", "value"),
116
+ State("window", "value"),
117
+ State("strategy", "value"),
118
+ State("ema1", "value"),
119
+ State("ema2", "value"),
120
+ State("closecross", "value")
121
+ )
122
+ def update_visuals(n_clicks, name, window, strategy, ema1, ema2, closecross):
123
+ if n_clicks <= 0 or not name:
124
+ return
125
+
126
+ # Clear existing files
127
+ open('assets/backtest_results.html', 'w').close()
128
+ open('assets/SMC.html', 'w').close()
129
+
130
+ ticker = symbols[symbols['NAME OF COMPANY'] == name]['YahooEquiv'].values[0]
131
+ data = fetch(ticker, '1mo', '15m')
132
+
133
+ fig = SMC(data=data, swing_hl_window_sz=window).plot(show=False).update_layout(title=dict(text=ticker))
134
+
135
+ print(strategy)
136
+ if strategy=='SMC':
137
+ smc_plot_backtest(data, 'assets/backtest_results.html', swing_hl=window)
138
+ elif strategy=='SMC with EMA':
139
+ smc_ema_plot_backtest(data, 'assets/backtest_results.html', ema1, ema2, closecross)
140
+
141
+ fig.write_html('assets/SMC.html')
142
+
143
+ if __name__ == "__main__":
144
+ # Clear initial files
145
+ open('assets/backtest_results.html', 'w').close()
146
+ open('assets/SMC.html', 'w').close()
147
+
148
+ app.run(debug=True)
data_fetcher.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import yfinance as yf
2
+
3
+ def fetch(symbol, period, interval):
4
+ df = yf.download(symbol, period=period, interval=interval)
5
+ df.columns =df.columns.get_level_values(0)
6
+ return df
gradio_app.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from data_fetcher import fetch
3
+ from indicators import SMC
4
+ from strategies import smc_plot_backtest, smc_ema_plot_backtest
5
+ import pandas as pd
6
+
7
+ symbols = pd.read_csv('data/Ticker_List_NSE_India.csv')
8
+
9
+ def run(stock, strategy, swing_hl, ema1, ema2, cross_close):
10
+ ticker = symbols[symbols['NAME OF COMPANY'] == stock]['YahooEquiv'].values[0]
11
+ data = fetch(ticker, period='1mo', interval='15m')
12
+
13
+ smc_plot_backtest(data, 'test.html', swing_hl)
14
+
15
+ signal_plot = SMC(data=data, swing_hl_window_sz=swing_hl).plot(show=False).update_layout(title=dict(text=ticker))
16
+ backtest_plot = gr.Plot()
17
+
18
+ if strategy == "SMC":
19
+ backtest_plot = smc_plot_backtest(data, 'test.html', swing_hl)
20
+
21
+ if strategy == "SMC with EMA":
22
+ backtest_plot = smc_ema_plot_backtest(data, 'test.html', ema1, ema2, cross_close)
23
+
24
+ return signal_plot, backtest_plot
25
+
26
+
27
+ with gr.Blocks(fill_width=True) as app:
28
+ gr.Markdown(
29
+ '# Algorithmic Trading Dashboard'
30
+ )
31
+ stock = gr.Dropdown(symbols['NAME OF COMPANY'].unique().tolist(), label='Select Company', value=None)
32
+
33
+ with gr.Row():
34
+ strategy = gr.Dropdown(['SMC', 'SMC with EMA'], label='Strategy', value=None)
35
+ swing_hl = gr.Number(label="Swing High/Low Window Size", value=10, interactive=True)
36
+
37
+ @gr.render(inputs=[strategy])
38
+ def show_extra(strat):
39
+ if strat == "SMC with EMA":
40
+ with gr.Row():
41
+ ema1 = gr.Number(label='Fast EMA length', value=9)
42
+ ema2 = gr.Number(label='Slow EMA length', value=21)
43
+ cross_close = gr.Checkbox(label='Close trade on EMA crossover')
44
+ input = [stock, strategy, swing_hl, ema1, ema2, cross_close]
45
+
46
+ elif strat == "SMC":
47
+ input = [stock, strategy, swing_hl]
48
+ else:
49
+ input = []
50
+
51
+ btn.click(
52
+ run,
53
+ inputs=input,
54
+ outputs=[signal_plot, backtest_plot]
55
+ )
56
+
57
+ btn = gr.Button("Run")
58
+
59
+ with gr.Row():
60
+ signal_plot = gr.Plot(label='Signal plot')
61
+
62
+ with gr.Row():
63
+ backtest_plot = gr.Plot(label='Backtesting plot')
64
+
65
+ app.launch(debug=True)
indicators.py ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ import numpy as np
3
+ import plotly.graph_objects as go
4
+ from plotly.subplots import make_subplots
5
+
6
+ class SMC:
7
+ def __init__(self, data, swing_hl_window_sz=10):
8
+ self.data = data
9
+ self.data['Date'] = self.data.index.to_series()
10
+ self.swing_hl_window_sz = swing_hl_window_sz
11
+ self.order_blocks = self.order_block()
12
+
13
+ def backtest_buy_signal(self):
14
+ bull_ob = self.order_blocks[(self.order_blocks['OB']==1) & (self.order_blocks['MitigatedIndex']!=0)]
15
+ arr = np.zeros(len(self.data))
16
+ arr[bull_ob['MitigatedIndex'].apply(lambda x: int(x))] = 1
17
+ return arr
18
+
19
+ def backtest_sell_signal(self):
20
+ bear_ob = self.order_blocks[(self.order_blocks['OB'] == -1) & (self.order_blocks['MitigatedIndex'] != 0)]
21
+ arr = np.zeros(len(self.data))
22
+ arr[bear_ob['MitigatedIndex'].apply(lambda x: int(x))] = -1
23
+ return arr
24
+
25
+ def swing_highs_lows(self, window_size):
26
+ l = self.data['Low'].reset_index(drop=True)
27
+ h = self.data['High'].reset_index(drop=True)
28
+ swing_highs = (h.rolling(window_size, center=True).max() / h == 1.)
29
+ swing_lows = (l.rolling(window_size, center=True).min() / l == 1.)
30
+ return pd.DataFrame({'Date':self.data.index.to_series(), 'highs':swing_highs.values, 'lows':swing_lows.values})
31
+
32
+ def fvg(self):
33
+ """
34
+ FVG - Fair Value Gap
35
+ A fair value gap is when the previous high is lower than the next low if the current candle is bullish.
36
+ Or when the previous low is higher than the next high if the current candle is bearish.
37
+
38
+ parameters:
39
+
40
+ returns:
41
+ FVG = 1 if bullish fair value gap, -1 if bearish fair value gap
42
+ Top = the top of the fair value gap
43
+ Bottom = the bottom of the fair value gap
44
+ MitigatedIndex = the index of the candle that mitigated the fair value gap
45
+ """
46
+
47
+ fvg = np.where(
48
+ (
49
+ (self.data["High"].shift(1) < self.data["Low"].shift(-1))
50
+ & (self.data["Close"] > self.data["Open"])
51
+ )
52
+ | (
53
+ (self.data["Low"].shift(1) > self.data["High"].shift(-1))
54
+ & (self.data["Close"] < self.data["Open"])
55
+ ),
56
+ np.where(self.data["Close"] > self.data["Open"], 1, -1),
57
+ np.nan,
58
+ )
59
+
60
+ top = np.where(
61
+ ~np.isnan(fvg),
62
+ np.where(
63
+ self.data["Close"] > self.data["Open"],
64
+ self.data["Low"].shift(-1),
65
+ self.data["Low"].shift(1),
66
+ ),
67
+ np.nan,
68
+ )
69
+
70
+ bottom = np.where(
71
+ ~np.isnan(fvg),
72
+ np.where(
73
+ self.data["Close"] > self.data["Open"],
74
+ self.data["High"].shift(1),
75
+ self.data["High"].shift(-1),
76
+ ),
77
+ np.nan,
78
+ )
79
+
80
+ mitigated_index = np.zeros(len(self.data), dtype=np.int32)
81
+ for i in np.where(~np.isnan(fvg))[0]:
82
+ mask = np.zeros(len(self.data), dtype=np.bool_)
83
+ if fvg[i] == 1:
84
+ mask = self.data["Low"][i + 2:] <= top[i]
85
+ elif fvg[i] == -1:
86
+ mask = self.data["High"][i + 2:] >= bottom[i]
87
+ if np.any(mask):
88
+ j = np.argmax(mask) + i + 2
89
+ mitigated_index[i] = j
90
+
91
+ mitigated_index = np.where(np.isnan(fvg), np.nan, mitigated_index)
92
+
93
+ return pd.concat(
94
+ [
95
+ pd.Series(fvg.flatten(), name="FVG"),
96
+ pd.Series(top.flatten(), name="Top"),
97
+ pd.Series(bottom.flatten(), name="Bottom"),
98
+ pd.Series(mitigated_index.flatten(), name="MitigatedIndex"),
99
+ ],
100
+ axis=1,
101
+ )
102
+
103
+ def order_block(self, imb_perc=.1, join_consecutive=True):
104
+ hl = self.swing_highs_lows(self.swing_hl_window_sz)
105
+
106
+ ob = np.where(
107
+ (
108
+ ((self.data["High"]*((100+imb_perc)/100)) < self.data["Low"].shift(-2))
109
+ & ((hl['lows']==True) | (hl['lows'].shift(1)==True))
110
+ )
111
+ | (
112
+ (self.data["Low"] > (self.data["High"].shift(-2)*((100+imb_perc)/100)))
113
+ & ((hl['highs']==True) | (hl['highs'].shift(1)==True))
114
+ ),
115
+ np.where(((hl['lows']==True) | (hl['lows'].shift(1)==True)), 1, -1),
116
+ np.nan,
117
+ )
118
+
119
+ # print(ob)
120
+
121
+ top = np.where(
122
+ ~np.isnan(ob),
123
+ np.where(
124
+ self.data["Close"] > self.data["Open"],
125
+ self.data["Low"].shift(-2),
126
+ self.data["Low"],
127
+ ),
128
+ np.nan,
129
+ )
130
+
131
+ bottom = np.where(
132
+ ~np.isnan(ob),
133
+ np.where(
134
+ self.data["Close"] > self.data["Open"],
135
+ self.data["High"],
136
+ self.data["High"].shift(-2),
137
+ ),
138
+ np.nan,
139
+ )
140
+
141
+ # if join_consecutive:
142
+ # for i in range(len(ob) - 1):
143
+ # if ob[i] == ob[i + 1]:
144
+ # top[i + 1] = max(top[i], top[i + 1])
145
+ # bottom[i + 1] = min(bottom[i], bottom[i + 1])
146
+ # ob[i] = top[i] = bottom[i] = np.nan
147
+
148
+ mitigated_index = np.zeros(len(self.data), dtype=np.int32)
149
+ for i in np.where(~np.isnan(ob))[0]:
150
+ mask = np.zeros(len(self.data), dtype=np.bool_)
151
+ if ob[i] == 1:
152
+ mask = self.data["Low"][i + 3:] <= top[i]
153
+ elif ob[i] == -1:
154
+ mask = self.data["High"][i + 3:] >= bottom[i]
155
+ if np.any(mask):
156
+ j = np.argmax(mask) + i + 3
157
+ mitigated_index[i] = int(j)
158
+ ob = ob.flatten()
159
+ mitigated_index1 = np.where(np.isnan(ob), np.nan, mitigated_index)
160
+
161
+ return pd.concat(
162
+ [
163
+ pd.Series(ob.flatten(), name="OB"),
164
+ pd.Series(top.flatten(), name="Top"),
165
+ pd.Series(bottom.flatten(), name="Bottom"),
166
+ pd.Series(mitigated_index1.flatten(), name="MitigatedIndex"),
167
+ ],
168
+ axis=1,
169
+ ).dropna(subset=['OB'])
170
+
171
+ def plot(self, swing_hl=True, show=True):
172
+ fig = make_subplots(1, 1)
173
+
174
+ # plot the candle stick graph
175
+ fig.add_trace(go.Candlestick(x=self.data.index.to_series(),
176
+ open=self.data['Open'],
177
+ high=self.data['High'],
178
+ low=self.data['Low'],
179
+ close=self.data['Close'],
180
+ name='ohlc'))
181
+
182
+ # grab first and last observations from df.date and make a continuous date range from that
183
+ dt_all = pd.date_range(start=self.data['Date'].iloc[0], end=self.data['Date'].iloc[-1], freq='5min')
184
+
185
+ # check which dates from your source that also accur in the continuous date range
186
+ dt_obs = [d.strftime("%Y-%m-%d %H:%M:%S") for d in self.data['Date']]
187
+
188
+ # isolate missing timestamps
189
+ dt_breaks = [d for d in dt_all.strftime("%Y-%m-%d %H:%M:%S").tolist() if not d in dt_obs]
190
+
191
+ # adjust xaxis for rangebreaks
192
+ fig.update_xaxes(rangebreaks=[dict(dvalue=5 * 60 * 1000, values=dt_breaks)])
193
+
194
+ print(self.order_blocks.head())
195
+ print(self.order_blocks.index.to_list())
196
+
197
+ ob_df = self.data.iloc[self.order_blocks.index.to_list()]
198
+ # print(ob_df)
199
+
200
+ fig.add_trace(go.Scatter(
201
+ x=ob_df['Date'],
202
+ y=ob_df['Low'],
203
+ name="Order Block",
204
+ mode='markers',
205
+ marker_symbol='diamond-dot',
206
+ marker_size=13,
207
+ marker_line_width=2,
208
+ # offsetgroup=0,
209
+ ))
210
+
211
+ if swing_hl:
212
+ hl = self.swing_highs_lows(self.swing_hl_window_sz)
213
+ h = hl[(hl['highs']==True)]
214
+ l = hl[hl['lows']==True]
215
+ # print(h)
216
+ # exit(0)
217
+ fig.add_trace(go.Scatter(
218
+ x=h['Date'],
219
+ y=self.data[self.data.Date.isin(h['Date'])]['High']*(100.1/100),
220
+ mode='markers',
221
+ marker_symbol="triangle-up-dot",
222
+ marker_size=10,
223
+ name='Swing High',
224
+ # offsetgroup=2,
225
+ ))
226
+ fig.add_trace(go.Scatter(
227
+ x=l['Date'],
228
+ y=self.data[self.data.Date.isin(l['Date'])]['Low']*(99.9/100),
229
+ mode='markers',
230
+ marker_symbol="triangle-down-dot",
231
+ marker_size=10,
232
+ name='Swing Low',
233
+ marker_color='red',
234
+ # offsetgroup=2,
235
+ ))
236
+
237
+ fig.update_layout(xaxis_rangeslider_visible=False)
238
+ if show:
239
+ fig.show()
240
+ return fig
241
+
242
+
243
+ def EMA(array, n):
244
+ return pd.Series(array).ewm(span=n, adjust=False).mean()
245
+
246
+ if __name__ == "__main__":
247
+ from data_fetcher import fetch
248
+ data = fetch('ICICIBANK.NS', period='1mo', interval='15m')
249
+ # data = fetch('RELIANCE.NS', period='1mo', interval='15m')
250
+
251
+ # print(SMC(data).backtest_buy_signal())
252
+ SMC(data).plot()
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ backtesting==0.3.3
2
+ numpy==2.2.0
3
+ pandas==2.2.3
4
+ bokeh==3.1.0
5
+ yfinance==0.2.50
6
+ plotly==5.24.1
7
+ dash==2.18.2
8
+ dash-bootstrap-components==1.6.0
strategies.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from backtesting import Backtest, Strategy
2
+ from backtesting.lib import SignalStrategy, TrailingStrategy
3
+ from indicators import SMC, EMA
4
+ from data_fetcher import fetch
5
+ import pandas as pd
6
+
7
+ class SMC_test(Strategy):
8
+ swing_hl = 10
9
+ def init(self):
10
+ super().init()
11
+
12
+ self.smc_b = self.I(self.smc_buy, data=self.data.df, swing_hl=self.swing_hl)
13
+ self.smc_s = self.I(self.smc_sell, data=self.data.df, swing_hl=self.swing_hl)
14
+
15
+
16
+ def next(self):
17
+ price = self.data.Close[-1]
18
+ current_time = self.data.index[-1]
19
+
20
+ if self.smc_b[-1] == 1:
21
+ self.buy(sl=.95 * price, tp=1.05 * price)
22
+ if self.smc_s[-1] == -1:
23
+ self.sell(tp=.95 * price, sl=1.05 * price)
24
+
25
+ # Additionally, set aggressive stop-loss on trades that have been open
26
+ # for more than two days
27
+ for trade in self.trades:
28
+ if current_time - trade.entry_time > pd.Timedelta('2 days'):
29
+ if trade.is_long:
30
+ trade.sl = max(trade.sl, self.data.Low[-1])
31
+ else:
32
+ trade.sl = min(trade.sl, self.data.High[-1])
33
+
34
+
35
+ def smc_buy(self, data, swing_hl):
36
+ return SMC(data, swing_hl).backtest_buy_signal()
37
+
38
+ def smc_sell(self, data, swing_hl):
39
+ return SMC(data, swing_hl).backtest_sell_signal()
40
+
41
+ class SMC_ema(SignalStrategy, TrailingStrategy):
42
+ ema1 = 9
43
+ ema2 = 21
44
+ close_on_crossover = False
45
+
46
+ def init(self):
47
+ super().init()
48
+
49
+ self.smc_b = self.I(self.smc_buy, self.data.df)
50
+ self.smc_s = self.I(self.smc_sell, self.data.df)
51
+
52
+
53
+ close = self.data.Close
54
+
55
+ self.ma1 = self.I(EMA, close, self.ema1)
56
+ self.ma2 = self.I(EMA, close, self.ema2)
57
+
58
+
59
+ def next(self):
60
+ price = self.data.Close[-1]
61
+ current_time = self.data.index[-1]
62
+
63
+ if self.smc_b[-1] == 1 and self.ma1 > self.ma2:
64
+ self.buy(sl=.95 * price, tp=1.05 * price)
65
+ if self.smc_s[-1] == -1 and self.ma1 < self.ma2:
66
+ self.sell(tp=.95 * price, sl=1.05 * price)
67
+
68
+ # Additionally, set aggressive stop-loss on trades that have been open
69
+ # for more than two days
70
+ for trade in self.trades:
71
+ if current_time - trade.entry_time > pd.Timedelta('2 days'):
72
+ if trade.is_long:
73
+ trade.sl = max(trade.sl, self.data.Low[-1])
74
+ else:
75
+ trade.sl = min(trade.sl, self.data.High[-1])
76
+
77
+ # Close the trade if there is a moving average crossover in opposite direction
78
+ if self.close_on_crossover:
79
+ for trade in self.trades:
80
+ if trade.is_long and self.ma1 < self.ma2:
81
+ trade.close()
82
+ if trade.is_short and self.ma1 > self.ma2:
83
+ trade.close()
84
+
85
+ def smc_buy(self, data):
86
+ return SMC(data).backtest_buy_signal()
87
+
88
+ def smc_sell(self, data):
89
+ return SMC(data).backtest_sell_signal()
90
+
91
+ def smc_plot_backtest(data, filename, swing_hl, **kwargs):
92
+ bt = Backtest(data, SMC_test, **kwargs)
93
+ bt.run(swing_hl=swing_hl)
94
+ print('runned')
95
+ return bt.plot(filename=filename, open_browser=False)
96
+
97
+ def smc_ema_plot_backtest(data, filename, ema1, ema2, closecross, **kwargs):
98
+ bt = Backtest(data, SMC_ema, **kwargs)
99
+ bt.run(ema1=ema1, ema2=ema2, close_on_crossover=closecross)
100
+ return bt.plot(filename=filename, open_browser=False)
101
+
102
+
103
+ if __name__ == "__main__":
104
+ data = fetch('ICICIBANK.NS', period='1mo', interval='15m')
105
+ bt = Backtest(data, SMC_ema, commission=.002)
106
+
107
+ bt.run(ema1 = 9, ema2 = 21, close_on_crossover=True)
108
+ bt.plot()