QuantumLearner commited on
Commit
6c95f9b
·
verified ·
1 Parent(s): 7fce304

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +240 -0
app.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import yfinance as yf
3
+ import pandas as pd
4
+ import numpy as np
5
+ import plotly.graph_objs as go
6
+ from datetime import datetime, timedelta
7
+ from plotly.subplots import make_subplots
8
+
9
+ # Set Streamlit page configuration
10
+ st.set_page_config(page_title="Pivot Point-RSI Volatility Trading Strategy", layout="wide")
11
+
12
+ # App title
13
+ st.title("Pivot Point-RSI Volatility Trading Strategy")
14
+
15
+ # Description of the app
16
+ st.markdown('''
17
+ This tool executes a trading strategy that combines Pivot Points, RSI, and ATR to identify buy and sell signals.
18
+ It works by calculating support and resistance levels using Pivot Points, determining market momentum through RSI, and adjusting
19
+ stop-loss and target levels based on market volatility using ATR.
20
+
21
+ The strategy finds the best possible parameters through optimization.
22
+ You can also manually input your own settings. The app provides buy/sell signals, an equity curve, and performance metrics based on historical data to help evaluate the strategy.
23
+ ''')
24
+
25
+ # Sidebar: How to use the app
26
+ with st.sidebar.expander("How to Use", expanded=False):
27
+ st.write('''
28
+ 1. Select the asset and date range for backtesting.
29
+ 2. Click "Run Strategy" to generate results.
30
+ 3. View the equity curve, buy/sell signals, and performance metrics.
31
+ 4. Adjust the parameters post-run to fine-tune results.
32
+ ''')
33
+
34
+ # Sidebar: Select Ticker and Date Range
35
+ with st.sidebar.expander("Select Ticker and Date Range", expanded=True):
36
+ ticker = st.text_input("Asset Symbol", value="ASML.AS", help="Ticker Symbol or Cryptocurrency Pair (e.g., AAPL, BTC-USD)")
37
+ start_date = st.date_input("Start Date", value=datetime(2020, 1, 1), help="Select the start date for historical data.")
38
+ end_date = st.date_input("End Date", value=datetime.today() + timedelta(days=1), help="Select the end date for historical data.")
39
+
40
+ # Download data
41
+ @st.cache_data
42
+ def download_data(ticker, start, end):
43
+ data = yf.download(ticker, start=start, end=end)
44
+ return data
45
+
46
+ # Function to execute and cache strategy results
47
+ @st.cache_data
48
+ def execute_strategy(data, strategy_params):
49
+ data_with_signals = trading_strategy(data.copy(), **strategy_params)
50
+ profit, equity_curve, accuracy_rate = backtest_strategy(data_with_signals)
51
+ return data_with_signals, profit, equity_curve, accuracy_rate, strategy_params
52
+
53
+ # Trading strategy function
54
+ def trading_strategy(data, rsi_period, rsi_oversold, rsi_overbought, atr_period, stop_loss_multiplier, target_multiplier, tolerance):
55
+ data['high24'] = data['High'].rolling(window=24).max()
56
+ data['low24'] = data['Low'].rolling(window=24).min()
57
+ data['close24'] = data['Close'].rolling(window=24).mean()
58
+
59
+ data['pivot'] = (data['high24'] + data['low24'] + data['close24']) / 3
60
+ data['support'] = (2 * data['pivot'].rolling(window=12).min()) - data['high24']
61
+ data['resistance'] = (2 * data['pivot'].rolling(window=12).max()) - data['low24']
62
+
63
+ delta = data['Close'].diff()
64
+ up, down = delta.copy(), delta.copy()
65
+ up[up < 0] = 0
66
+ down[down > 0] = 0
67
+
68
+ roll_up1 = up.ewm(span=rsi_period).mean()
69
+ roll_down1 = down.abs().ewm(span=rsi_period).mean()
70
+ RS1 = roll_up1 / roll_down1
71
+ data['rsi'] = 100.0 - (100.0 / (1.0 + RS1))
72
+
73
+ data['HL'] = data['High'] - data['Low']
74
+ data['absHC'] = abs(data['High'] - data['Close'].shift())
75
+ data['absLC'] = abs(data['Low'] - data['Close'].shift())
76
+ data['TR'] = data[['HL', 'absHC', 'absLC']].max(axis=1)
77
+ data['atr'] = data['TR'].rolling(window=atr_period).mean()
78
+
79
+ data['signal'] = np.where(
80
+ (data['Close'] >= data['support'] * (1 - tolerance)) & (data['Close'] <= data['support'] * (1 + tolerance)) & (data['rsi'] < rsi_oversold), 'Buy',
81
+ np.where((data['Close'] >= data['resistance'] * (1 - tolerance)) & (data['Close'] <= data['resistance'] * (1 + tolerance)) & (data['rsi'] > rsi_overbought), 'Sell', 'Hold')
82
+ )
83
+
84
+ data['stop_loss'] = data['Close'] - stop_loss_multiplier * data['atr']
85
+ data['target'] = data['Close'] + target_multiplier * data['atr']
86
+
87
+ return data
88
+
89
+ # Backtest function
90
+ def backtest_strategy(data):
91
+ initial_capital = 100000
92
+ position = 0
93
+ capital = initial_capital
94
+ equity_curve = []
95
+ correct_signals = 0
96
+ total_signals = 0
97
+
98
+ for index, row in data.iterrows():
99
+ if row['signal'] == 'Buy' and position == 0:
100
+ position = 1
101
+ entry_price = row['Close']
102
+ stop_loss = row['stop_loss']
103
+ target = row['target']
104
+
105
+ elif row['signal'] == 'Sell' and position == 0:
106
+ position = -1
107
+ entry_price = row['Close']
108
+ stop_loss = row['stop_loss']
109
+ target = row['target']
110
+
111
+ if position == 1:
112
+ if row['Low'] <= stop_loss:
113
+ capital += (stop_loss - entry_price) * 100
114
+ position = 0
115
+ elif row['High'] >= target:
116
+ capital += (target - entry_price) * 100
117
+ position = 0
118
+ elif row['signal'] == 'Sell':
119
+ capital += (row['Close'] - entry_price) * 100
120
+ position = 0
121
+
122
+ elif position == -1:
123
+ if row['High'] >= stop_loss:
124
+ capital += (entry_price - stop_loss) * 100
125
+ position = 0
126
+ elif row['Low'] <= target:
127
+ capital += (entry_price - target) * 100
128
+ position = 0
129
+ elif row['signal'] == 'Buy':
130
+ capital += (entry_price - row['Close']) * 100
131
+ position = 0
132
+
133
+ equity_curve.append(capital)
134
+
135
+ final_profit = equity_curve[-1] - initial_capital
136
+ return final_profit, equity_curve, 0
137
+
138
+ # Optimized parameters (fixed)
139
+ optimized_params = {
140
+ 'rsi_period': 13,
141
+ 'rsi_oversold': 30,
142
+ 'rsi_overbought': 70,
143
+ 'atr_period': 14,
144
+ 'stop_loss_multiplier': 2.25,
145
+ 'target_multiplier': 4.5,
146
+ 'tolerance': 0.01
147
+ }
148
+
149
+ # Run button to initiate the strategy
150
+ run_button = st.sidebar.button("Run Strategy")
151
+
152
+ # Running the strategy
153
+ if run_button:
154
+ # Download data
155
+ data = download_data(ticker, start_date, end_date)
156
+
157
+ # Execute the strategy with optimized parameters
158
+ data_with_signals, profit, equity_curve, _, best_params = execute_strategy(data, optimized_params)
159
+
160
+ # Cache results in session state
161
+ st.session_state['data_with_signals'] = data_with_signals
162
+ st.session_state['equity_curve'] = equity_curve
163
+ st.session_state['best_params'] = best_params
164
+
165
+ # Display optimized parameters
166
+ st.json(best_params)
167
+
168
+ # If session state contains data, allow for post-run parameter adjustments
169
+ if 'data_with_signals' in st.session_state:
170
+ st.sidebar.markdown("### Adjust Parameters Post-Run")
171
+
172
+ adjusted_rsi_period = st.sidebar.slider("RSI Period", 5, 30, st.session_state['best_params']['rsi_period'], step=1, help="RSI period defines the sensitivity of the RSI. Lower values make the RSI more sensitive to price changes, generating more signals. Higher values smooth out price movements, reducing the number of signals.")
173
+ adjusted_stop_loss_multiplier = st.sidebar.slider("Stop Loss Multiplier", 1.0, 3.0, st.session_state['best_params']['stop_loss_multiplier'], step=0.1, help="Stop Loss Multiplier adjusts how far the stop-loss is set from the entry price. Lower values keep the stop-loss closer, reducing risk but increasing the chance of being stopped out. Higher values place the stop-loss further away, allowing more flexibility but with higher potential risk.")
174
+ adjusted_target_multiplier = st.sidebar.slider("Target Multiplier", 1.0, 5.0, st.session_state['best_params']['target_multiplier'], step=0.1, help="Target Multiplier adjusts how far the profit target is set from the entry price. Lower values take profits earlier but reduce potential gains. Higher values aim for larger profits but increase the chance of price reversal before hitting the target.")
175
+ adjusted_tolerance = st.sidebar.slider("Signal Tolerance", 0.0, 0.05, st.session_state['best_params']['tolerance'], step=0.01, help="Signal Tolerance adjusts how strictly the strategy follows support and resistance levels. Lower values make signals more precise but reduce their frequency. Higher values increase the frequency of signals by being more lenient, which can lead to false signals.")
176
+
177
+ # Recalculate the strategy with adjusted parameters
178
+ updated_params = {
179
+ 'rsi_period': adjusted_rsi_period,
180
+ 'rsi_oversold': 30,
181
+ 'rsi_overbought': 70,
182
+ 'atr_period': 14,
183
+ 'stop_loss_multiplier': adjusted_stop_loss_multiplier,
184
+ 'target_multiplier': adjusted_target_multiplier,
185
+ 'tolerance': adjusted_tolerance
186
+ }
187
+
188
+ updated_data = trading_strategy(st.session_state['data_with_signals'].copy(), **updated_params)
189
+
190
+ # Plotting with adjustments for easier comparison of x-axis
191
+ fig = make_subplots(rows=3, cols=1, shared_xaxes=True,
192
+ subplot_titles=("Price and Bollinger Bands", "RSI", "Equity Curve"),
193
+ vertical_spacing=0.12) # Increased vertical spacing
194
+
195
+ # Price and signal plot
196
+ fig.add_trace(go.Scatter(x=updated_data.index, y=updated_data['Close'], mode='lines', name='Close Price'))
197
+ fig.add_trace(go.Scatter(x=updated_data.index, y=updated_data['support'], mode='lines', name='Support Level', line=dict(dash='dash')))
198
+ fig.add_trace(go.Scatter(x=updated_data.index, y=updated_data['resistance'], mode='lines', name='Resistance Level', line=dict(dash='dash')))
199
+
200
+ # Buy/Sell Signals with increased marker size
201
+ buy_signals = updated_data[updated_data['signal'] == 'Buy']
202
+ sell_signals = updated_data[updated_data['signal'] == 'Sell']
203
+ fig.add_trace(go.Scatter(x=buy_signals.index, y=buy_signals['Close'], mode='markers', name='Buy Signal',
204
+ marker=dict(color='green', symbol='triangle-up', size=12))) # Increased size
205
+ fig.add_trace(go.Scatter(x=sell_signals.index, y=sell_signals['Close'], mode='markers', name='Sell Signal',
206
+ marker=dict(color='red', symbol='triangle-down', size=12))) # Increased size
207
+
208
+ # RSI Plot with black line, red upper threshold, and green lower threshold
209
+ fig.add_trace(go.Scatter(x=updated_data.index, y=updated_data['rsi'], mode='lines', name='RSI', line=dict(color='black')), row=2, col=1)
210
+ fig.add_shape(type="line", x0=updated_data.index[0], x1=updated_data.index[-1], y0=30, y1=30,
211
+ line=dict(dash='dash', color='green'), row=2, col=1) # Lower threshold in green
212
+ fig.add_shape(type="line", x0=updated_data.index[0], x1=updated_data.index[-1], y0=70, y1=70,
213
+ line=dict(dash='dash', color='red'), row=2, col=1) # Upper threshold in red
214
+
215
+ # Equity Curve Plot
216
+ fig.add_trace(go.Scatter(x=updated_data.index, y=st.session_state['equity_curve'], mode='lines', name='Equity Curve'), row=3, col=1)
217
+
218
+ # Move the legend outside the plot and increase gap
219
+ fig.update_layout(
220
+ title=f'{ticker} Strategy with Adjusted Parameters',
221
+ xaxis_title='Date',
222
+ yaxis_title='Price',
223
+ legend=dict(orientation="h", yanchor="bottom", y=1.05, xanchor="center", x=0.5, traceorder='normal', valign='top', borderwidth=0),
224
+ height=1000, # Increase the height for better visibility
225
+ margin=dict(t=30, b=30), # Adjust margins for better spacing
226
+ font=dict(size=12), # Adjust font size for better readability
227
+ # Subplot title style adjustment for black color
228
+ annotations=[dict(font=dict(color="black", size=14)) for _ in range(3)] # Adjusts all subplot titles to black
229
+ )
230
+
231
+ # Display the chart
232
+ st.plotly_chart(fig, use_container_width=True)
233
+
234
+ hide_streamlit_style = """
235
+ <style>
236
+ #MainMenu {visibility: hidden;}
237
+ footer {visibility: hidden;}
238
+ </style>
239
+ """
240
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)