AlirezaX2 commited on
Commit
561706e
·
1 Parent(s): a84c47e

remove env

Browse files
Files changed (6) hide show
  1. .gitattributes +35 -0
  2. .gitignore +2 -0
  3. README.md +12 -0
  4. backtester.py +5 -1
  5. create_mock_data.py +1 -1
  6. dashboard.py +83 -6
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
.gitignore CHANGED
@@ -10,4 +10,6 @@ wheels/
10
  .venv
11
  # Data files
12
  *.parquet
 
13
 
 
 
10
  .venv
11
  # Data files
12
  *.parquet
13
+ *.csv
14
 
15
+ .env
README.md CHANGED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: PennyStockShortBacktester
3
+ emoji: 👁
4
+ colorFrom: purple
5
+ colorTo: green
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
10
+ # Penny Stock Short Backtester
11
+ This application analyzes penny stock gaps and backtests short strategies.
12
+
backtester.py CHANGED
@@ -12,6 +12,7 @@ def run_backtest(
12
  end_date,
13
  max_trades_per_day,
14
  commission_amount=2.0,
 
15
  ):
16
  """
17
  Runs the backtest logic on the provided dataframe with given parameters.
@@ -43,8 +44,11 @@ def run_backtest(
43
  "marketsession_30min",
44
  "marketsession_60min",
45
  "marketsession_120min",
46
- "marketsession_high",
47
  ]
 
 
 
48
 
49
  for current_date in dates:
50
  countertradesperday = 0
 
12
  end_date,
13
  max_trades_per_day,
14
  commission_amount=2.0,
15
+ include_high_spike=False,
16
  ):
17
  """
18
  Runs the backtest logic on the provided dataframe with given parameters.
 
44
  "marketsession_30min",
45
  "marketsession_60min",
46
  "marketsession_120min",
47
+ # "marketsession_high",
48
  ]
49
+
50
+ if include_high_spike:
51
+ ms_columns.append("marketsession_high")
52
 
53
  for current_date in dates:
54
  countertradesperday = 0
create_mock_data.py CHANGED
@@ -35,7 +35,7 @@ def create_mock_data():
35
  )
36
 
37
  df = pd.DataFrame(rows)
38
- filename = "marketsession_post_polygon_2020-01-01_2025-12-01.parquet_with_premarketvolume900K_marketcap1B.parquet"
39
  df.to_parquet(filename)
40
  print(f"Mock data created: {filename}")
41
 
 
35
  )
36
 
37
  df = pd.DataFrame(rows)
38
+ filename = "marketsession_post_polygon_2020-01-01_2026-01-01.parquet_with_premarketvolume900K_marketcap1B.parquet"
39
  df.to_parquet(filename)
40
  print(f"Mock data created: {filename}")
41
 
dashboard.py CHANGED
@@ -48,14 +48,24 @@ commission_amount_input = pn.widgets.FloatInput(
48
 
49
  # Date Range (default based on user script)
50
  default_start = pd.Timestamp("2024-10-07").date()
51
- default_end = pd.Timestamp("2025-12-01").date() # Future date from user script
52
- date_range_input = pn.widgets.DateRangeSlider(
53
- name="Date Range",
 
 
 
 
 
 
 
 
54
  start=pd.Timestamp("2020-01-01").date(),
55
  end=pd.Timestamp("2026-01-01").date(),
56
- value=(default_start, default_end),
57
  )
58
 
 
 
 
59
  run_button = pn.widgets.Button(name="Run Backtest", button_type="primary")
60
 
61
 
@@ -85,7 +95,9 @@ def execute_backtest(event=None):
85
  init_cap = initial_capital_input.value
86
  max_trades = max_trades_input.value
87
  comm_amt = commission_amount_input.value
88
- start_date, end_date = date_range_input.value
 
 
89
 
90
  trades_df = run_backtest(
91
  current_df,
@@ -97,6 +109,7 @@ def execute_backtest(event=None):
97
  end_date,
98
  max_trades,
99
  commission_amount=comm_amt,
 
100
  )
101
 
102
  if trades_df.empty:
@@ -154,6 +167,66 @@ def execute_backtest(event=None):
154
  yformatter="%.0f",
155
  )
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  # 2. Cumulative Commission
158
  comm_plot = analysis_df.hvplot.line(
159
  x="index",
@@ -245,6 +318,7 @@ def execute_backtest(event=None):
245
  comm_plot,
246
  capital_days_plot,
247
  profit_days_plot,
 
248
  ),
249
  ),
250
  pn.Row(pnl_dist_plot, ticker_plot),
@@ -288,7 +362,10 @@ sidebar = pn.Column(
288
  initial_capital_input,
289
  max_trades_input,
290
  commission_amount_input,
291
- date_range_input,
 
 
 
292
  run_button,
293
  pn.layout.Divider(),
294
  "**Note**: Ensure `HF_TOKEN` is set in `.env` to download data.",
 
48
 
49
  # Date Range (default based on user script)
50
  default_start = pd.Timestamp("2024-10-07").date()
51
+ default_end = pd.Timestamp("2026-01-01").date() # Future date from user script
52
+
53
+ start_date_input = pn.widgets.DatePicker(
54
+ name="Start Date",
55
+ value=default_start,
56
+ start=pd.Timestamp("2020-01-01").date(),
57
+ end=pd.Timestamp("2026-01-01").date(),
58
+ )
59
+ end_date_input = pn.widgets.DatePicker(
60
+ name="End Date",
61
+ value=default_end,
62
  start=pd.Timestamp("2020-01-01").date(),
63
  end=pd.Timestamp("2026-01-01").date(),
 
64
  )
65
 
66
+ high_spike_checkbox = pn.widgets.Checkbox(name="Include High Spike (marketsession_high)", value=False)
67
+ high_spike_text = pn.pane.Markdown("this is high spike", styles={'font-size': '0.9em', 'color': 'gray', 'margin-top': '-10px'})
68
+
69
  run_button = pn.widgets.Button(name="Run Backtest", button_type="primary")
70
 
71
 
 
95
  init_cap = initial_capital_input.value
96
  max_trades = max_trades_input.value
97
  comm_amt = commission_amount_input.value
98
+ start_date = start_date_input.value
99
+ end_date = end_date_input.value
100
+ include_high = high_spike_checkbox.value
101
 
102
  trades_df = run_backtest(
103
  current_df,
 
109
  end_date,
110
  max_trades,
111
  commission_amount=comm_amt,
112
+ include_high_spike=include_high,
113
  )
114
 
115
  if trades_df.empty:
 
167
  yformatter="%.0f",
168
  )
169
 
170
+ # 1c. Monthly Performance
171
+ # We need to calculate monthly return %.
172
+ # Strategy: Group by Month.
173
+ # Monthly PnL = Sum(pnl)
174
+ # Monthly Return % = Monthly PnL / Start of Month Capital * 100
175
+ # Start of Month Capital can be approximated by:
176
+ # First trade of month 'capital_net' - trade 'pnl' -> This is capital before the first trade of the month.
177
+ # (Note: This neglects capital changes if there were no trades for a while, but it's a good approximation for active trading)
178
+
179
+ analysis_df["month"] = pd.to_datetime(analysis_df["date"]).dt.to_period("M")
180
+ monthly_stats = (
181
+ analysis_df.groupby("month")
182
+ .agg(
183
+ {
184
+ "pnl": "sum",
185
+ "pnl_gross": "sum",
186
+ "capital_net": "first", # We'll adjust this
187
+ "pnl": "sum", # Re-asserting sum
188
+ }
189
+ )
190
+ .reset_index()
191
+ )
192
+
193
+ # To get the true start capital for the month, we find the first trade of that month and subtract its PnL from its ending capital_net.
194
+ # A more robust way:
195
+ # For each month, find the first trade index.
196
+ monthly_data = []
197
+ for m in analysis_df["month"].unique():
198
+ month_trades = analysis_df[analysis_df["month"] == m]
199
+ if month_trades.empty:
200
+ continue
201
+
202
+ first_trade = month_trades.iloc[0]
203
+ start_cap = first_trade["capital_net"] - first_trade["pnl"]
204
+
205
+ total_pnl = month_trades["pnl"].sum()
206
+ return_pct = (total_pnl / start_cap * 100) if start_cap != 0 else 0
207
+
208
+ monthly_data.append({
209
+ "month": str(m),
210
+ "pnl": total_pnl,
211
+ "return_pct": return_pct
212
+ })
213
+
214
+ monthly_df = pd.DataFrame(monthly_data)
215
+
216
+ monthly_plot = monthly_df.hvplot.bar(
217
+ x="month",
218
+ y="return_pct",
219
+ title="Monthly Performance (%)",
220
+ ylabel="Return (%)",
221
+ xlabel="Month",
222
+ grid=True,
223
+ height=300,
224
+ responsive=True,
225
+ color="#9C27B0",
226
+ yformatter="%.1f%%",
227
+ rot=45,
228
+ ) if not monthly_df.empty else pn.pane.Markdown("No monthly data")
229
+
230
  # 2. Cumulative Commission
231
  comm_plot = analysis_df.hvplot.line(
232
  x="index",
 
318
  comm_plot,
319
  capital_days_plot,
320
  profit_days_plot,
321
+ monthly_plot,
322
  ),
323
  ),
324
  pn.Row(pnl_dist_plot, ticker_plot),
 
362
  initial_capital_input,
363
  max_trades_input,
364
  commission_amount_input,
365
+ start_date_input,
366
+ end_date_input,
367
+ high_spike_checkbox,
368
+ high_spike_text,
369
  run_button,
370
  pn.layout.Divider(),
371
  "**Note**: Ensure `HF_TOKEN` is set in `.env` to download data.",