hkblockchaintechnology commited on
Commit
d7e2e17
·
verified ·
1 Parent(s): e435696

Stock Pilot sync 2026-10-20T11:09:18Z

Browse files
stockpilot/README.md CHANGED
@@ -34,6 +34,8 @@ With an existing virtualenv, use `.venv/bin/stockpilot ...` instead.
34
  - **Data:** Yahoo Finance chart API by default, cached in SQLite. Quotes are
35
  synthetic from the latest completed bar and marked delayed. An optional
36
  Webull OpenAPI feed can be enabled after a market-data subscription is active.
 
 
37
  - **Features:** 56 causal technical features across RSI, MACD, Bollinger Bands,
38
  ATR/ADX, Ichimoku, Fibonacci position, VWAP, EMAs, volume, pivots, and time of
39
  day. Features never use future bars.
 
34
  - **Data:** Yahoo Finance chart API by default, cached in SQLite. Quotes are
35
  synthetic from the latest completed bar and marked delayed. An optional
36
  Webull OpenAPI feed can be enabled after a market-data subscription is active.
37
+ Bars are fetched once per interval and reused between loop cycles to avoid
38
+ hammering the provider; snapshots come from the cache.
39
  - **Features:** 56 causal technical features across RSI, MACD, Bollinger Bands,
40
  ATR/ADX, Ichimoku, Fibonacci position, VWAP, EMAs, volume, pivots, and time of
41
  day. Features never use future bars.
stockpilot/data/reports/reasons2_20261020_105645.json ADDED
@@ -0,0 +1,632 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "reasons2",
3
+ "generated_at": "2026-10-20T10:56:45.661270+00:00",
4
+ "start": "2026-09-28T13:30:00+00:00",
5
+ "end": "2026-10-19T20:00:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 1249,
8
+ "model": {
9
+ "rows": 310873,
10
+ "bottom_positive": 7964,
11
+ "top_positive": 8090,
12
+ "bottom_auc": 0.915165762263474,
13
+ "top_auc": 0.917786181112047,
14
+ "bottom_cv_auc": 0.8872258147013774,
15
+ "top_cv_auc": 0.8932111752120084,
16
+ "trained_at": "2026-10-20T10:47:01.310267+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.85,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 10024.94,
32
+ "total_return_pct": 0.249,
33
+ "max_drawdown_pct": -0.105,
34
+ "sharpe_daily_annualized": 5.844,
35
+ "trades": 215,
36
+ "win_rate_pct": 61.4,
37
+ "profit_factor": 2.222,
38
+ "avg_trade_pnl": 0.4273,
39
+ "avg_win": 1.2657,
40
+ "avg_loss": -0.9061,
41
+ "gross_profit": 167.07,
42
+ "gross_loss": 75.2,
43
+ "exposure_pct": 42.19,
44
+ "bars": 1249,
45
+ "days": 16
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "MRNA",
50
+ "trades": 6,
51
+ "pnl": 31.47,
52
+ "wins": 3,
53
+ "win_rate_pct": 50.0
54
+ },
55
+ {
56
+ "symbol": "ALAB",
57
+ "trades": 5,
58
+ "pnl": 18.12,
59
+ "wins": 3,
60
+ "win_rate_pct": 60.0
61
+ },
62
+ {
63
+ "symbol": "TXN",
64
+ "trades": 4,
65
+ "pnl": 17.26,
66
+ "wins": 4,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "STX",
71
+ "trades": 2,
72
+ "pnl": 7.24,
73
+ "wins": 2,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "NBIS",
78
+ "trades": 5,
79
+ "pnl": 5.41,
80
+ "wins": 4,
81
+ "win_rate_pct": 80.0
82
+ },
83
+ {
84
+ "symbol": "ABNB",
85
+ "trades": 6,
86
+ "pnl": 4.8,
87
+ "wins": 4,
88
+ "win_rate_pct": 66.7
89
+ },
90
+ {
91
+ "symbol": "TER",
92
+ "trades": 3,
93
+ "pnl": 4.19,
94
+ "wins": 3,
95
+ "win_rate_pct": 100.0
96
+ },
97
+ {
98
+ "symbol": "COST",
99
+ "trades": 2,
100
+ "pnl": 4.14,
101
+ "wins": 2,
102
+ "win_rate_pct": 100.0
103
+ },
104
+ {
105
+ "symbol": "DDOG",
106
+ "trades": 5,
107
+ "pnl": 3.78,
108
+ "wins": 4,
109
+ "win_rate_pct": 80.0
110
+ },
111
+ {
112
+ "symbol": "LIN",
113
+ "trades": 2,
114
+ "pnl": 3.22,
115
+ "wins": 2,
116
+ "win_rate_pct": 100.0
117
+ },
118
+ {
119
+ "symbol": "ADI",
120
+ "trades": 6,
121
+ "pnl": 3.16,
122
+ "wins": 4,
123
+ "win_rate_pct": 66.7
124
+ },
125
+ {
126
+ "symbol": "NXPI",
127
+ "trades": 6,
128
+ "pnl": 2.4,
129
+ "wins": 4,
130
+ "win_rate_pct": 66.7
131
+ },
132
+ {
133
+ "symbol": "LRCX",
134
+ "trades": 2,
135
+ "pnl": 2.27,
136
+ "wins": 2,
137
+ "win_rate_pct": 100.0
138
+ },
139
+ {
140
+ "symbol": "CDNS",
141
+ "trades": 5,
142
+ "pnl": 2.25,
143
+ "wins": 4,
144
+ "win_rate_pct": 80.0
145
+ },
146
+ {
147
+ "symbol": "MSTR",
148
+ "trades": 2,
149
+ "pnl": 2.23,
150
+ "wins": 2,
151
+ "win_rate_pct": 100.0
152
+ },
153
+ {
154
+ "symbol": "IDXX",
155
+ "trades": 2,
156
+ "pnl": 2.22,
157
+ "wins": 2,
158
+ "win_rate_pct": 100.0
159
+ },
160
+ {
161
+ "symbol": "HON",
162
+ "trades": 4,
163
+ "pnl": 1.95,
164
+ "wins": 4,
165
+ "win_rate_pct": 100.0
166
+ },
167
+ {
168
+ "symbol": "ALNY",
169
+ "trades": 2,
170
+ "pnl": 1.66,
171
+ "wins": 2,
172
+ "win_rate_pct": 100.0
173
+ },
174
+ {
175
+ "symbol": "ADBE",
176
+ "trades": 3,
177
+ "pnl": 1.63,
178
+ "wins": 2,
179
+ "win_rate_pct": 66.7
180
+ },
181
+ {
182
+ "symbol": "SHOP",
183
+ "trades": 4,
184
+ "pnl": 1.6,
185
+ "wins": 4,
186
+ "win_rate_pct": 100.0
187
+ },
188
+ {
189
+ "symbol": "AMAT",
190
+ "trades": 1,
191
+ "pnl": 1.54,
192
+ "wins": 1,
193
+ "win_rate_pct": 100.0
194
+ },
195
+ {
196
+ "symbol": "TSLA",
197
+ "trades": 1,
198
+ "pnl": 1.53,
199
+ "wins": 1,
200
+ "win_rate_pct": 100.0
201
+ },
202
+ {
203
+ "symbol": "INTU",
204
+ "trades": 3,
205
+ "pnl": 1.41,
206
+ "wins": 2,
207
+ "win_rate_pct": 66.7
208
+ },
209
+ {
210
+ "symbol": "CTAS",
211
+ "trades": 1,
212
+ "pnl": 1.34,
213
+ "wins": 1,
214
+ "win_rate_pct": 100.0
215
+ },
216
+ {
217
+ "symbol": "HONA",
218
+ "trades": 6,
219
+ "pnl": 1.29,
220
+ "wins": 4,
221
+ "win_rate_pct": 66.7
222
+ },
223
+ {
224
+ "symbol": "MAR",
225
+ "trades": 4,
226
+ "pnl": 1.11,
227
+ "wins": 3,
228
+ "win_rate_pct": 75.0
229
+ },
230
+ {
231
+ "symbol": "WDAY",
232
+ "trades": 2,
233
+ "pnl": 1.08,
234
+ "wins": 2,
235
+ "win_rate_pct": 100.0
236
+ },
237
+ {
238
+ "symbol": "PANW",
239
+ "trades": 3,
240
+ "pnl": 0.99,
241
+ "wins": 2,
242
+ "win_rate_pct": 66.7
243
+ },
244
+ {
245
+ "symbol": "CRWD",
246
+ "trades": 3,
247
+ "pnl": 0.97,
248
+ "wins": 3,
249
+ "win_rate_pct": 100.0
250
+ },
251
+ {
252
+ "symbol": "GEHC",
253
+ "trades": 2,
254
+ "pnl": 0.9,
255
+ "wins": 2,
256
+ "win_rate_pct": 100.0
257
+ },
258
+ {
259
+ "symbol": "ISRG",
260
+ "trades": 5,
261
+ "pnl": 0.52,
262
+ "wins": 4,
263
+ "win_rate_pct": 80.0
264
+ },
265
+ {
266
+ "symbol": "GILD",
267
+ "trades": 2,
268
+ "pnl": 0.47,
269
+ "wins": 2,
270
+ "win_rate_pct": 100.0
271
+ },
272
+ {
273
+ "symbol": "AMZN",
274
+ "trades": 1,
275
+ "pnl": 0.46,
276
+ "wins": 1,
277
+ "win_rate_pct": 100.0
278
+ },
279
+ {
280
+ "symbol": "FTNT",
281
+ "trades": 1,
282
+ "pnl": 0.43,
283
+ "wins": 1,
284
+ "win_rate_pct": 100.0
285
+ },
286
+ {
287
+ "symbol": "AEP",
288
+ "trades": 1,
289
+ "pnl": 0.3,
290
+ "wins": 1,
291
+ "win_rate_pct": 100.0
292
+ },
293
+ {
294
+ "symbol": "PAYX",
295
+ "trades": 1,
296
+ "pnl": 0.28,
297
+ "wins": 1,
298
+ "win_rate_pct": 100.0
299
+ },
300
+ {
301
+ "symbol": "FANG",
302
+ "trades": 2,
303
+ "pnl": 0.27,
304
+ "wins": 1,
305
+ "win_rate_pct": 50.0
306
+ },
307
+ {
308
+ "symbol": "XEL",
309
+ "trades": 5,
310
+ "pnl": 0.22,
311
+ "wins": 3,
312
+ "win_rate_pct": 60.0
313
+ },
314
+ {
315
+ "symbol": "CPRT",
316
+ "trades": 2,
317
+ "pnl": 0.22,
318
+ "wins": 2,
319
+ "win_rate_pct": 100.0
320
+ },
321
+ {
322
+ "symbol": "PYPL",
323
+ "trades": 3,
324
+ "pnl": 0.19,
325
+ "wins": 3,
326
+ "win_rate_pct": 100.0
327
+ },
328
+ {
329
+ "symbol": "DXCM",
330
+ "trades": 2,
331
+ "pnl": 0.19,
332
+ "wins": 2,
333
+ "win_rate_pct": 100.0
334
+ },
335
+ {
336
+ "symbol": "FAST",
337
+ "trades": 1,
338
+ "pnl": 0.18,
339
+ "wins": 1,
340
+ "win_rate_pct": 100.0
341
+ },
342
+ {
343
+ "symbol": "PEP",
344
+ "trades": 1,
345
+ "pnl": 0.17,
346
+ "wins": 1,
347
+ "win_rate_pct": 100.0
348
+ },
349
+ {
350
+ "symbol": "ORLY",
351
+ "trades": 2,
352
+ "pnl": 0.17,
353
+ "wins": 2,
354
+ "win_rate_pct": 100.0
355
+ },
356
+ {
357
+ "symbol": "CSCO",
358
+ "trades": 2,
359
+ "pnl": 0.16,
360
+ "wins": 1,
361
+ "win_rate_pct": 50.0
362
+ },
363
+ {
364
+ "symbol": "KDP",
365
+ "trades": 1,
366
+ "pnl": 0.12,
367
+ "wins": 1,
368
+ "win_rate_pct": 100.0
369
+ },
370
+ {
371
+ "symbol": "NFLX",
372
+ "trades": 1,
373
+ "pnl": 0.11,
374
+ "wins": 1,
375
+ "win_rate_pct": 100.0
376
+ },
377
+ {
378
+ "symbol": "EXC",
379
+ "trades": 1,
380
+ "pnl": 0.07,
381
+ "wins": 1,
382
+ "win_rate_pct": 100.0
383
+ },
384
+ {
385
+ "symbol": "MNST",
386
+ "trades": 3,
387
+ "pnl": 0.07,
388
+ "wins": 2,
389
+ "win_rate_pct": 66.7
390
+ },
391
+ {
392
+ "symbol": "INTC",
393
+ "trades": 3,
394
+ "pnl": 0.06,
395
+ "wins": 2,
396
+ "win_rate_pct": 66.7
397
+ },
398
+ {
399
+ "symbol": "WDC",
400
+ "trades": 1,
401
+ "pnl": 0.04,
402
+ "wins": 1,
403
+ "win_rate_pct": 100.0
404
+ },
405
+ {
406
+ "symbol": "DASH",
407
+ "trades": 6,
408
+ "pnl": 0.03,
409
+ "wins": 3,
410
+ "win_rate_pct": 50.0
411
+ },
412
+ {
413
+ "symbol": "MDLZ",
414
+ "trades": 2,
415
+ "pnl": 0.02,
416
+ "wins": 1,
417
+ "win_rate_pct": 50.0
418
+ },
419
+ {
420
+ "symbol": "CMCSA",
421
+ "trades": 2,
422
+ "pnl": -0.04,
423
+ "wins": 1,
424
+ "win_rate_pct": 50.0
425
+ },
426
+ {
427
+ "symbol": "CCEP",
428
+ "trades": 2,
429
+ "pnl": -0.04,
430
+ "wins": 1,
431
+ "win_rate_pct": 50.0
432
+ },
433
+ {
434
+ "symbol": "PDD",
435
+ "trades": 3,
436
+ "pnl": -0.17,
437
+ "wins": 1,
438
+ "win_rate_pct": 33.3
439
+ },
440
+ {
441
+ "symbol": "WMT",
442
+ "trades": 1,
443
+ "pnl": -0.17,
444
+ "wins": 0,
445
+ "win_rate_pct": 0.0
446
+ },
447
+ {
448
+ "symbol": "SBUX",
449
+ "trades": 1,
450
+ "pnl": -0.25,
451
+ "wins": 0,
452
+ "win_rate_pct": 0.0
453
+ },
454
+ {
455
+ "symbol": "TRI",
456
+ "trades": 4,
457
+ "pnl": -0.3,
458
+ "wins": 1,
459
+ "win_rate_pct": 25.0
460
+ },
461
+ {
462
+ "symbol": "CRWV",
463
+ "trades": 3,
464
+ "pnl": -0.31,
465
+ "wins": 1,
466
+ "win_rate_pct": 33.3
467
+ },
468
+ {
469
+ "symbol": "MCHP",
470
+ "trades": 3,
471
+ "pnl": -0.35,
472
+ "wins": 1,
473
+ "win_rate_pct": 33.3
474
+ },
475
+ {
476
+ "symbol": "BKR",
477
+ "trades": 5,
478
+ "pnl": -0.37,
479
+ "wins": 1,
480
+ "win_rate_pct": 20.0
481
+ },
482
+ {
483
+ "symbol": "QCOM",
484
+ "trades": 2,
485
+ "pnl": -0.51,
486
+ "wins": 1,
487
+ "win_rate_pct": 50.0
488
+ },
489
+ {
490
+ "symbol": "ROST",
491
+ "trades": 2,
492
+ "pnl": -0.87,
493
+ "wins": 0,
494
+ "win_rate_pct": 0.0
495
+ },
496
+ {
497
+ "symbol": "AMGN",
498
+ "trades": 1,
499
+ "pnl": -0.87,
500
+ "wins": 0,
501
+ "win_rate_pct": 0.0
502
+ },
503
+ {
504
+ "symbol": "VRTX",
505
+ "trades": 1,
506
+ "pnl": -0.88,
507
+ "wins": 0,
508
+ "win_rate_pct": 0.0
509
+ },
510
+ {
511
+ "symbol": "RKLB",
512
+ "trades": 2,
513
+ "pnl": -0.93,
514
+ "wins": 0,
515
+ "win_rate_pct": 0.0
516
+ },
517
+ {
518
+ "symbol": "ODFL",
519
+ "trades": 5,
520
+ "pnl": -1.34,
521
+ "wins": 1,
522
+ "win_rate_pct": 20.0
523
+ },
524
+ {
525
+ "symbol": "APP",
526
+ "trades": 1,
527
+ "pnl": -1.4,
528
+ "wins": 0,
529
+ "win_rate_pct": 0.0
530
+ },
531
+ {
532
+ "symbol": "BKNG",
533
+ "trades": 2,
534
+ "pnl": -1.42,
535
+ "wins": 0,
536
+ "win_rate_pct": 0.0
537
+ },
538
+ {
539
+ "symbol": "ARM",
540
+ "trades": 1,
541
+ "pnl": -1.61,
542
+ "wins": 0,
543
+ "win_rate_pct": 0.0
544
+ },
545
+ {
546
+ "symbol": "AVGO",
547
+ "trades": 3,
548
+ "pnl": -1.66,
549
+ "wins": 1,
550
+ "win_rate_pct": 33.3
551
+ },
552
+ {
553
+ "symbol": "KLAC",
554
+ "trades": 2,
555
+ "pnl": -1.79,
556
+ "wins": 0,
557
+ "win_rate_pct": 0.0
558
+ },
559
+ {
560
+ "symbol": "MSFT",
561
+ "trades": 2,
562
+ "pnl": -2.14,
563
+ "wins": 0,
564
+ "win_rate_pct": 0.0
565
+ },
566
+ {
567
+ "symbol": "SPCX",
568
+ "trades": 6,
569
+ "pnl": -2.67,
570
+ "wins": 1,
571
+ "win_rate_pct": 16.7
572
+ },
573
+ {
574
+ "symbol": "SNPS",
575
+ "trades": 3,
576
+ "pnl": -3.75,
577
+ "wins": 0,
578
+ "win_rate_pct": 0.0
579
+ },
580
+ {
581
+ "symbol": "CEG",
582
+ "trades": 3,
583
+ "pnl": -4.27,
584
+ "wins": 1,
585
+ "win_rate_pct": 33.3
586
+ },
587
+ {
588
+ "symbol": "REGN",
589
+ "trades": 3,
590
+ "pnl": -6.8,
591
+ "wins": 0,
592
+ "win_rate_pct": 0.0
593
+ },
594
+ {
595
+ "symbol": "MRVL",
596
+ "trades": 1,
597
+ "pnl": -11.14,
598
+ "wins": 0,
599
+ "win_rate_pct": 0.0
600
+ }
601
+ ],
602
+ "per_exit_reason": [
603
+ {
604
+ "exit_reason": "model_exit",
605
+ "trades": 91,
606
+ "pnl": 89.08,
607
+ "wins": 84,
608
+ "win_rate_pct": 92.3
609
+ },
610
+ {
611
+ "exit_reason": "take_profit",
612
+ "trades": 43,
613
+ "pnl": 61.42,
614
+ "wins": 41,
615
+ "win_rate_pct": 95.3
616
+ },
617
+ {
618
+ "exit_reason": "flatten_all",
619
+ "trades": 1,
620
+ "pnl": 0.01,
621
+ "wins": 1,
622
+ "win_rate_pct": 100.0
623
+ },
624
+ {
625
+ "exit_reason": "stop_loss",
626
+ "trades": 80,
627
+ "pnl": -58.65,
628
+ "wins": 6,
629
+ "win_rate_pct": 7.5
630
+ }
631
+ ]
632
+ }
stockpilot/data/reports/reasons_20261020_105623.json ADDED
@@ -0,0 +1,602 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "reasons",
3
+ "generated_at": "2026-10-20T10:56:23.321598+00:00",
4
+ "start": "2026-09-28T13:30:00+00:00",
5
+ "end": "2026-10-19T20:00:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 1249,
8
+ "model": {
9
+ "rows": 310873,
10
+ "bottom_positive": 7964,
11
+ "top_positive": 8090,
12
+ "bottom_auc": 0.915165762263474,
13
+ "top_auc": 0.917786181112047,
14
+ "bottom_cv_auc": 0.8872258147013774,
15
+ "top_cv_auc": 0.8932111752120084,
16
+ "trained_at": "2026-10-20T10:47:01.310267+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.85,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 10024.94,
32
+ "total_return_pct": 0.249,
33
+ "max_drawdown_pct": -0.105,
34
+ "sharpe_daily_annualized": 5.844,
35
+ "trades": 215,
36
+ "win_rate_pct": 61.4,
37
+ "profit_factor": 2.222,
38
+ "avg_trade_pnl": 0.4273,
39
+ "avg_win": 1.2657,
40
+ "avg_loss": -0.9061,
41
+ "gross_profit": 167.07,
42
+ "gross_loss": 75.2,
43
+ "exposure_pct": 42.19,
44
+ "bars": 1249,
45
+ "days": 16
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "MRNA",
50
+ "trades": 6,
51
+ "pnl": 31.47,
52
+ "wins": 3,
53
+ "win_rate_pct": 50.0
54
+ },
55
+ {
56
+ "symbol": "ALAB",
57
+ "trades": 5,
58
+ "pnl": 18.12,
59
+ "wins": 3,
60
+ "win_rate_pct": 60.0
61
+ },
62
+ {
63
+ "symbol": "TXN",
64
+ "trades": 4,
65
+ "pnl": 17.26,
66
+ "wins": 4,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "STX",
71
+ "trades": 2,
72
+ "pnl": 7.24,
73
+ "wins": 2,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "NBIS",
78
+ "trades": 5,
79
+ "pnl": 5.41,
80
+ "wins": 4,
81
+ "win_rate_pct": 80.0
82
+ },
83
+ {
84
+ "symbol": "ABNB",
85
+ "trades": 6,
86
+ "pnl": 4.8,
87
+ "wins": 4,
88
+ "win_rate_pct": 66.7
89
+ },
90
+ {
91
+ "symbol": "TER",
92
+ "trades": 3,
93
+ "pnl": 4.19,
94
+ "wins": 3,
95
+ "win_rate_pct": 100.0
96
+ },
97
+ {
98
+ "symbol": "COST",
99
+ "trades": 2,
100
+ "pnl": 4.14,
101
+ "wins": 2,
102
+ "win_rate_pct": 100.0
103
+ },
104
+ {
105
+ "symbol": "DDOG",
106
+ "trades": 5,
107
+ "pnl": 3.78,
108
+ "wins": 4,
109
+ "win_rate_pct": 80.0
110
+ },
111
+ {
112
+ "symbol": "LIN",
113
+ "trades": 2,
114
+ "pnl": 3.22,
115
+ "wins": 2,
116
+ "win_rate_pct": 100.0
117
+ },
118
+ {
119
+ "symbol": "ADI",
120
+ "trades": 6,
121
+ "pnl": 3.16,
122
+ "wins": 4,
123
+ "win_rate_pct": 66.7
124
+ },
125
+ {
126
+ "symbol": "NXPI",
127
+ "trades": 6,
128
+ "pnl": 2.4,
129
+ "wins": 4,
130
+ "win_rate_pct": 66.7
131
+ },
132
+ {
133
+ "symbol": "LRCX",
134
+ "trades": 2,
135
+ "pnl": 2.27,
136
+ "wins": 2,
137
+ "win_rate_pct": 100.0
138
+ },
139
+ {
140
+ "symbol": "CDNS",
141
+ "trades": 5,
142
+ "pnl": 2.25,
143
+ "wins": 4,
144
+ "win_rate_pct": 80.0
145
+ },
146
+ {
147
+ "symbol": "MSTR",
148
+ "trades": 2,
149
+ "pnl": 2.23,
150
+ "wins": 2,
151
+ "win_rate_pct": 100.0
152
+ },
153
+ {
154
+ "symbol": "IDXX",
155
+ "trades": 2,
156
+ "pnl": 2.22,
157
+ "wins": 2,
158
+ "win_rate_pct": 100.0
159
+ },
160
+ {
161
+ "symbol": "HON",
162
+ "trades": 4,
163
+ "pnl": 1.95,
164
+ "wins": 4,
165
+ "win_rate_pct": 100.0
166
+ },
167
+ {
168
+ "symbol": "ALNY",
169
+ "trades": 2,
170
+ "pnl": 1.66,
171
+ "wins": 2,
172
+ "win_rate_pct": 100.0
173
+ },
174
+ {
175
+ "symbol": "ADBE",
176
+ "trades": 3,
177
+ "pnl": 1.63,
178
+ "wins": 2,
179
+ "win_rate_pct": 66.7
180
+ },
181
+ {
182
+ "symbol": "SHOP",
183
+ "trades": 4,
184
+ "pnl": 1.6,
185
+ "wins": 4,
186
+ "win_rate_pct": 100.0
187
+ },
188
+ {
189
+ "symbol": "AMAT",
190
+ "trades": 1,
191
+ "pnl": 1.54,
192
+ "wins": 1,
193
+ "win_rate_pct": 100.0
194
+ },
195
+ {
196
+ "symbol": "TSLA",
197
+ "trades": 1,
198
+ "pnl": 1.53,
199
+ "wins": 1,
200
+ "win_rate_pct": 100.0
201
+ },
202
+ {
203
+ "symbol": "INTU",
204
+ "trades": 3,
205
+ "pnl": 1.41,
206
+ "wins": 2,
207
+ "win_rate_pct": 66.7
208
+ },
209
+ {
210
+ "symbol": "CTAS",
211
+ "trades": 1,
212
+ "pnl": 1.34,
213
+ "wins": 1,
214
+ "win_rate_pct": 100.0
215
+ },
216
+ {
217
+ "symbol": "HONA",
218
+ "trades": 6,
219
+ "pnl": 1.29,
220
+ "wins": 4,
221
+ "win_rate_pct": 66.7
222
+ },
223
+ {
224
+ "symbol": "MAR",
225
+ "trades": 4,
226
+ "pnl": 1.11,
227
+ "wins": 3,
228
+ "win_rate_pct": 75.0
229
+ },
230
+ {
231
+ "symbol": "WDAY",
232
+ "trades": 2,
233
+ "pnl": 1.08,
234
+ "wins": 2,
235
+ "win_rate_pct": 100.0
236
+ },
237
+ {
238
+ "symbol": "PANW",
239
+ "trades": 3,
240
+ "pnl": 0.99,
241
+ "wins": 2,
242
+ "win_rate_pct": 66.7
243
+ },
244
+ {
245
+ "symbol": "CRWD",
246
+ "trades": 3,
247
+ "pnl": 0.97,
248
+ "wins": 3,
249
+ "win_rate_pct": 100.0
250
+ },
251
+ {
252
+ "symbol": "GEHC",
253
+ "trades": 2,
254
+ "pnl": 0.9,
255
+ "wins": 2,
256
+ "win_rate_pct": 100.0
257
+ },
258
+ {
259
+ "symbol": "ISRG",
260
+ "trades": 5,
261
+ "pnl": 0.52,
262
+ "wins": 4,
263
+ "win_rate_pct": 80.0
264
+ },
265
+ {
266
+ "symbol": "GILD",
267
+ "trades": 2,
268
+ "pnl": 0.47,
269
+ "wins": 2,
270
+ "win_rate_pct": 100.0
271
+ },
272
+ {
273
+ "symbol": "AMZN",
274
+ "trades": 1,
275
+ "pnl": 0.46,
276
+ "wins": 1,
277
+ "win_rate_pct": 100.0
278
+ },
279
+ {
280
+ "symbol": "FTNT",
281
+ "trades": 1,
282
+ "pnl": 0.43,
283
+ "wins": 1,
284
+ "win_rate_pct": 100.0
285
+ },
286
+ {
287
+ "symbol": "AEP",
288
+ "trades": 1,
289
+ "pnl": 0.3,
290
+ "wins": 1,
291
+ "win_rate_pct": 100.0
292
+ },
293
+ {
294
+ "symbol": "PAYX",
295
+ "trades": 1,
296
+ "pnl": 0.28,
297
+ "wins": 1,
298
+ "win_rate_pct": 100.0
299
+ },
300
+ {
301
+ "symbol": "FANG",
302
+ "trades": 2,
303
+ "pnl": 0.27,
304
+ "wins": 1,
305
+ "win_rate_pct": 50.0
306
+ },
307
+ {
308
+ "symbol": "XEL",
309
+ "trades": 5,
310
+ "pnl": 0.22,
311
+ "wins": 3,
312
+ "win_rate_pct": 60.0
313
+ },
314
+ {
315
+ "symbol": "CPRT",
316
+ "trades": 2,
317
+ "pnl": 0.22,
318
+ "wins": 2,
319
+ "win_rate_pct": 100.0
320
+ },
321
+ {
322
+ "symbol": "PYPL",
323
+ "trades": 3,
324
+ "pnl": 0.19,
325
+ "wins": 3,
326
+ "win_rate_pct": 100.0
327
+ },
328
+ {
329
+ "symbol": "DXCM",
330
+ "trades": 2,
331
+ "pnl": 0.19,
332
+ "wins": 2,
333
+ "win_rate_pct": 100.0
334
+ },
335
+ {
336
+ "symbol": "FAST",
337
+ "trades": 1,
338
+ "pnl": 0.18,
339
+ "wins": 1,
340
+ "win_rate_pct": 100.0
341
+ },
342
+ {
343
+ "symbol": "PEP",
344
+ "trades": 1,
345
+ "pnl": 0.17,
346
+ "wins": 1,
347
+ "win_rate_pct": 100.0
348
+ },
349
+ {
350
+ "symbol": "ORLY",
351
+ "trades": 2,
352
+ "pnl": 0.17,
353
+ "wins": 2,
354
+ "win_rate_pct": 100.0
355
+ },
356
+ {
357
+ "symbol": "CSCO",
358
+ "trades": 2,
359
+ "pnl": 0.16,
360
+ "wins": 1,
361
+ "win_rate_pct": 50.0
362
+ },
363
+ {
364
+ "symbol": "KDP",
365
+ "trades": 1,
366
+ "pnl": 0.12,
367
+ "wins": 1,
368
+ "win_rate_pct": 100.0
369
+ },
370
+ {
371
+ "symbol": "NFLX",
372
+ "trades": 1,
373
+ "pnl": 0.11,
374
+ "wins": 1,
375
+ "win_rate_pct": 100.0
376
+ },
377
+ {
378
+ "symbol": "EXC",
379
+ "trades": 1,
380
+ "pnl": 0.07,
381
+ "wins": 1,
382
+ "win_rate_pct": 100.0
383
+ },
384
+ {
385
+ "symbol": "MNST",
386
+ "trades": 3,
387
+ "pnl": 0.07,
388
+ "wins": 2,
389
+ "win_rate_pct": 66.7
390
+ },
391
+ {
392
+ "symbol": "INTC",
393
+ "trades": 3,
394
+ "pnl": 0.06,
395
+ "wins": 2,
396
+ "win_rate_pct": 66.7
397
+ },
398
+ {
399
+ "symbol": "WDC",
400
+ "trades": 1,
401
+ "pnl": 0.04,
402
+ "wins": 1,
403
+ "win_rate_pct": 100.0
404
+ },
405
+ {
406
+ "symbol": "DASH",
407
+ "trades": 6,
408
+ "pnl": 0.03,
409
+ "wins": 3,
410
+ "win_rate_pct": 50.0
411
+ },
412
+ {
413
+ "symbol": "MDLZ",
414
+ "trades": 2,
415
+ "pnl": 0.02,
416
+ "wins": 1,
417
+ "win_rate_pct": 50.0
418
+ },
419
+ {
420
+ "symbol": "CMCSA",
421
+ "trades": 2,
422
+ "pnl": -0.04,
423
+ "wins": 1,
424
+ "win_rate_pct": 50.0
425
+ },
426
+ {
427
+ "symbol": "CCEP",
428
+ "trades": 2,
429
+ "pnl": -0.04,
430
+ "wins": 1,
431
+ "win_rate_pct": 50.0
432
+ },
433
+ {
434
+ "symbol": "PDD",
435
+ "trades": 3,
436
+ "pnl": -0.17,
437
+ "wins": 1,
438
+ "win_rate_pct": 33.3
439
+ },
440
+ {
441
+ "symbol": "WMT",
442
+ "trades": 1,
443
+ "pnl": -0.17,
444
+ "wins": 0,
445
+ "win_rate_pct": 0.0
446
+ },
447
+ {
448
+ "symbol": "SBUX",
449
+ "trades": 1,
450
+ "pnl": -0.25,
451
+ "wins": 0,
452
+ "win_rate_pct": 0.0
453
+ },
454
+ {
455
+ "symbol": "TRI",
456
+ "trades": 4,
457
+ "pnl": -0.3,
458
+ "wins": 1,
459
+ "win_rate_pct": 25.0
460
+ },
461
+ {
462
+ "symbol": "CRWV",
463
+ "trades": 3,
464
+ "pnl": -0.31,
465
+ "wins": 1,
466
+ "win_rate_pct": 33.3
467
+ },
468
+ {
469
+ "symbol": "MCHP",
470
+ "trades": 3,
471
+ "pnl": -0.35,
472
+ "wins": 1,
473
+ "win_rate_pct": 33.3
474
+ },
475
+ {
476
+ "symbol": "BKR",
477
+ "trades": 5,
478
+ "pnl": -0.37,
479
+ "wins": 1,
480
+ "win_rate_pct": 20.0
481
+ },
482
+ {
483
+ "symbol": "QCOM",
484
+ "trades": 2,
485
+ "pnl": -0.51,
486
+ "wins": 1,
487
+ "win_rate_pct": 50.0
488
+ },
489
+ {
490
+ "symbol": "ROST",
491
+ "trades": 2,
492
+ "pnl": -0.87,
493
+ "wins": 0,
494
+ "win_rate_pct": 0.0
495
+ },
496
+ {
497
+ "symbol": "AMGN",
498
+ "trades": 1,
499
+ "pnl": -0.87,
500
+ "wins": 0,
501
+ "win_rate_pct": 0.0
502
+ },
503
+ {
504
+ "symbol": "VRTX",
505
+ "trades": 1,
506
+ "pnl": -0.88,
507
+ "wins": 0,
508
+ "win_rate_pct": 0.0
509
+ },
510
+ {
511
+ "symbol": "RKLB",
512
+ "trades": 2,
513
+ "pnl": -0.93,
514
+ "wins": 0,
515
+ "win_rate_pct": 0.0
516
+ },
517
+ {
518
+ "symbol": "ODFL",
519
+ "trades": 5,
520
+ "pnl": -1.34,
521
+ "wins": 1,
522
+ "win_rate_pct": 20.0
523
+ },
524
+ {
525
+ "symbol": "APP",
526
+ "trades": 1,
527
+ "pnl": -1.4,
528
+ "wins": 0,
529
+ "win_rate_pct": 0.0
530
+ },
531
+ {
532
+ "symbol": "BKNG",
533
+ "trades": 2,
534
+ "pnl": -1.42,
535
+ "wins": 0,
536
+ "win_rate_pct": 0.0
537
+ },
538
+ {
539
+ "symbol": "ARM",
540
+ "trades": 1,
541
+ "pnl": -1.61,
542
+ "wins": 0,
543
+ "win_rate_pct": 0.0
544
+ },
545
+ {
546
+ "symbol": "AVGO",
547
+ "trades": 3,
548
+ "pnl": -1.66,
549
+ "wins": 1,
550
+ "win_rate_pct": 33.3
551
+ },
552
+ {
553
+ "symbol": "KLAC",
554
+ "trades": 2,
555
+ "pnl": -1.79,
556
+ "wins": 0,
557
+ "win_rate_pct": 0.0
558
+ },
559
+ {
560
+ "symbol": "MSFT",
561
+ "trades": 2,
562
+ "pnl": -2.14,
563
+ "wins": 0,
564
+ "win_rate_pct": 0.0
565
+ },
566
+ {
567
+ "symbol": "SPCX",
568
+ "trades": 6,
569
+ "pnl": -2.67,
570
+ "wins": 1,
571
+ "win_rate_pct": 16.7
572
+ },
573
+ {
574
+ "symbol": "SNPS",
575
+ "trades": 3,
576
+ "pnl": -3.75,
577
+ "wins": 0,
578
+ "win_rate_pct": 0.0
579
+ },
580
+ {
581
+ "symbol": "CEG",
582
+ "trades": 3,
583
+ "pnl": -4.27,
584
+ "wins": 1,
585
+ "win_rate_pct": 33.3
586
+ },
587
+ {
588
+ "symbol": "REGN",
589
+ "trades": 3,
590
+ "pnl": -6.8,
591
+ "wins": 0,
592
+ "win_rate_pct": 0.0
593
+ },
594
+ {
595
+ "symbol": "MRVL",
596
+ "trades": 1,
597
+ "pnl": -11.14,
598
+ "wins": 0,
599
+ "win_rate_pct": 0.0
600
+ }
601
+ ]
602
+ }
stockpilot/data/reports/wf_entry90_f1_20261020_105952.json ADDED
@@ -0,0 +1,289 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "wf_entry90_f1",
3
+ "generated_at": "2026-10-20T10:59:52.127968+00:00",
4
+ "start": "2026-09-16T13:30:00+00:00",
5
+ "end": "2026-09-25T19:55:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 624,
8
+ "model": {
9
+ "rows": 123588,
10
+ "bottom_positive": 3097,
11
+ "top_positive": 3320,
12
+ "bottom_auc": 0.9286175360617559,
13
+ "top_auc": 0.929439890970407,
14
+ "bottom_cv_auc": 0.8762567127509834,
15
+ "top_cv_auc": 0.8843654091667135,
16
+ "trained_at": "2026-10-20T10:58:08.454584+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.9,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 10021.49,
32
+ "total_return_pct": 0.215,
33
+ "max_drawdown_pct": -0.129,
34
+ "sharpe_daily_annualized": 9.582,
35
+ "trades": 51,
36
+ "win_rate_pct": 62.75,
37
+ "profit_factor": 5.814,
38
+ "avg_trade_pnl": 2.0328,
39
+ "avg_win": 3.9127,
40
+ "avg_loss": -1.1334,
41
+ "gross_profit": 125.21,
42
+ "gross_loss": 21.53,
43
+ "exposure_pct": 30.45,
44
+ "bars": 624,
45
+ "days": 8
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "ALAB",
50
+ "trades": 6,
51
+ "pnl": 95.05,
52
+ "wins": 5,
53
+ "win_rate_pct": 83.3
54
+ },
55
+ {
56
+ "symbol": "META",
57
+ "trades": 1,
58
+ "pnl": 5.47,
59
+ "wins": 1,
60
+ "win_rate_pct": 100.0
61
+ },
62
+ {
63
+ "symbol": "ADI",
64
+ "trades": 1,
65
+ "pnl": 2.84,
66
+ "wins": 1,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "MRVL",
71
+ "trades": 2,
72
+ "pnl": 2.46,
73
+ "wins": 2,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "AMAT",
78
+ "trades": 1,
79
+ "pnl": 1.6,
80
+ "wins": 1,
81
+ "win_rate_pct": 100.0
82
+ },
83
+ {
84
+ "symbol": "MRNA",
85
+ "trades": 5,
86
+ "pnl": 1.43,
87
+ "wins": 3,
88
+ "win_rate_pct": 60.0
89
+ },
90
+ {
91
+ "symbol": "ALNY",
92
+ "trades": 1,
93
+ "pnl": 1.19,
94
+ "wins": 1,
95
+ "win_rate_pct": 100.0
96
+ },
97
+ {
98
+ "symbol": "LRCX",
99
+ "trades": 1,
100
+ "pnl": 0.93,
101
+ "wins": 1,
102
+ "win_rate_pct": 100.0
103
+ },
104
+ {
105
+ "symbol": "TER",
106
+ "trades": 3,
107
+ "pnl": 0.8,
108
+ "wins": 2,
109
+ "win_rate_pct": 66.7
110
+ },
111
+ {
112
+ "symbol": "CRWD",
113
+ "trades": 1,
114
+ "pnl": 0.75,
115
+ "wins": 1,
116
+ "win_rate_pct": 100.0
117
+ },
118
+ {
119
+ "symbol": "CDNS",
120
+ "trades": 1,
121
+ "pnl": 0.61,
122
+ "wins": 1,
123
+ "win_rate_pct": 100.0
124
+ },
125
+ {
126
+ "symbol": "FTNT",
127
+ "trades": 1,
128
+ "pnl": 0.56,
129
+ "wins": 1,
130
+ "win_rate_pct": 100.0
131
+ },
132
+ {
133
+ "symbol": "AVGO",
134
+ "trades": 1,
135
+ "pnl": 0.47,
136
+ "wins": 1,
137
+ "win_rate_pct": 100.0
138
+ },
139
+ {
140
+ "symbol": "DXCM",
141
+ "trades": 1,
142
+ "pnl": 0.46,
143
+ "wins": 1,
144
+ "win_rate_pct": 100.0
145
+ },
146
+ {
147
+ "symbol": "TRI",
148
+ "trades": 1,
149
+ "pnl": 0.45,
150
+ "wins": 1,
151
+ "win_rate_pct": 100.0
152
+ },
153
+ {
154
+ "symbol": "BKNG",
155
+ "trades": 1,
156
+ "pnl": 0.38,
157
+ "wins": 1,
158
+ "win_rate_pct": 100.0
159
+ },
160
+ {
161
+ "symbol": "LITE",
162
+ "trades": 1,
163
+ "pnl": 0.32,
164
+ "wins": 1,
165
+ "win_rate_pct": 100.0
166
+ },
167
+ {
168
+ "symbol": "MSTR",
169
+ "trades": 1,
170
+ "pnl": 0.23,
171
+ "wins": 1,
172
+ "win_rate_pct": 100.0
173
+ },
174
+ {
175
+ "symbol": "PDD",
176
+ "trades": 1,
177
+ "pnl": 0.17,
178
+ "wins": 1,
179
+ "win_rate_pct": 100.0
180
+ },
181
+ {
182
+ "symbol": "PLTR",
183
+ "trades": 1,
184
+ "pnl": 0.14,
185
+ "wins": 1,
186
+ "win_rate_pct": 100.0
187
+ },
188
+ {
189
+ "symbol": "GEHC",
190
+ "trades": 1,
191
+ "pnl": -0.04,
192
+ "wins": 0,
193
+ "win_rate_pct": 0.0
194
+ },
195
+ {
196
+ "symbol": "RKLB",
197
+ "trades": 2,
198
+ "pnl": -0.14,
199
+ "wins": 1,
200
+ "win_rate_pct": 50.0
201
+ },
202
+ {
203
+ "symbol": "BKR",
204
+ "trades": 1,
205
+ "pnl": -0.15,
206
+ "wins": 0,
207
+ "win_rate_pct": 0.0
208
+ },
209
+ {
210
+ "symbol": "TSLA",
211
+ "trades": 1,
212
+ "pnl": -0.58,
213
+ "wins": 0,
214
+ "win_rate_pct": 0.0
215
+ },
216
+ {
217
+ "symbol": "NBIS",
218
+ "trades": 5,
219
+ "pnl": -0.61,
220
+ "wins": 3,
221
+ "win_rate_pct": 60.0
222
+ },
223
+ {
224
+ "symbol": "HONA",
225
+ "trades": 1,
226
+ "pnl": -0.67,
227
+ "wins": 0,
228
+ "win_rate_pct": 0.0
229
+ },
230
+ {
231
+ "symbol": "KLAC",
232
+ "trades": 1,
233
+ "pnl": -0.73,
234
+ "wins": 0,
235
+ "win_rate_pct": 0.0
236
+ },
237
+ {
238
+ "symbol": "DDOG",
239
+ "trades": 2,
240
+ "pnl": -1.4,
241
+ "wins": 0,
242
+ "win_rate_pct": 0.0
243
+ },
244
+ {
245
+ "symbol": "IDXX",
246
+ "trades": 1,
247
+ "pnl": -1.65,
248
+ "wins": 0,
249
+ "win_rate_pct": 0.0
250
+ },
251
+ {
252
+ "symbol": "ARM",
253
+ "trades": 2,
254
+ "pnl": -2.97,
255
+ "wins": 0,
256
+ "win_rate_pct": 0.0
257
+ },
258
+ {
259
+ "symbol": "PANW",
260
+ "trades": 2,
261
+ "pnl": -3.67,
262
+ "wins": 0,
263
+ "win_rate_pct": 0.0
264
+ }
265
+ ],
266
+ "per_exit_reason": [
267
+ {
268
+ "exit_reason": "model_exit",
269
+ "trades": 29,
270
+ "pnl": 92.93,
271
+ "wins": 27,
272
+ "win_rate_pct": 93.1
273
+ },
274
+ {
275
+ "exit_reason": "take_profit",
276
+ "trades": 5,
277
+ "pnl": 31.29,
278
+ "wins": 5,
279
+ "win_rate_pct": 100.0
280
+ },
281
+ {
282
+ "exit_reason": "stop_loss",
283
+ "trades": 17,
284
+ "pnl": -20.54,
285
+ "wins": 0,
286
+ "win_rate_pct": 0.0
287
+ }
288
+ ]
289
+ }
stockpilot/data/reports/wf_entry90_f2_20261020_110319.json ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "wf_entry90_f2",
3
+ "generated_at": "2026-10-20T11:03:19.821582+00:00",
4
+ "start": "2026-09-28T13:30:00+00:00",
5
+ "end": "2026-10-07T19:55:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 624,
8
+ "model": {
9
+ "rows": 185984,
10
+ "bottom_positive": 4719,
11
+ "top_positive": 4917,
12
+ "bottom_auc": 0.9222607206668713,
13
+ "top_auc": 0.9239758042455313,
14
+ "bottom_cv_auc": 0.8827475558726079,
15
+ "top_cv_auc": 0.8895076776138559,
16
+ "trained_at": "2026-10-20T11:00:51.174795+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.9,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 10013.96,
32
+ "total_return_pct": 0.14,
33
+ "max_drawdown_pct": -0.043,
34
+ "sharpe_daily_annualized": 8.838,
35
+ "trades": 35,
36
+ "win_rate_pct": 62.86,
37
+ "profit_factor": 4.49,
38
+ "avg_trade_pnl": 0.7573,
39
+ "avg_win": 1.5501,
40
+ "avg_loss": -0.5842,
41
+ "gross_profit": 34.1,
42
+ "gross_loss": 7.59,
43
+ "exposure_pct": 15.06,
44
+ "bars": 624,
45
+ "days": 8
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "ALAB",
50
+ "trades": 2,
51
+ "pnl": 12.98,
52
+ "wins": 2,
53
+ "win_rate_pct": 100.0
54
+ },
55
+ {
56
+ "symbol": "NBIS",
57
+ "trades": 3,
58
+ "pnl": 5.53,
59
+ "wins": 3,
60
+ "win_rate_pct": 100.0
61
+ },
62
+ {
63
+ "symbol": "MSTR",
64
+ "trades": 2,
65
+ "pnl": 2.23,
66
+ "wins": 2,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "TER",
71
+ "trades": 1,
72
+ "pnl": 1.61,
73
+ "wins": 1,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "TSLA",
78
+ "trades": 1,
79
+ "pnl": 1.46,
80
+ "wins": 1,
81
+ "win_rate_pct": 100.0
82
+ },
83
+ {
84
+ "symbol": "CDNS",
85
+ "trades": 1,
86
+ "pnl": 1.44,
87
+ "wins": 1,
88
+ "win_rate_pct": 100.0
89
+ },
90
+ {
91
+ "symbol": "ADI",
92
+ "trades": 1,
93
+ "pnl": 1.43,
94
+ "wins": 1,
95
+ "win_rate_pct": 100.0
96
+ },
97
+ {
98
+ "symbol": "DDOG",
99
+ "trades": 1,
100
+ "pnl": 1.37,
101
+ "wins": 1,
102
+ "win_rate_pct": 100.0
103
+ },
104
+ {
105
+ "symbol": "PANW",
106
+ "trades": 1,
107
+ "pnl": 1.25,
108
+ "wins": 1,
109
+ "win_rate_pct": 100.0
110
+ },
111
+ {
112
+ "symbol": "MRNA",
113
+ "trades": 1,
114
+ "pnl": 0.99,
115
+ "wins": 1,
116
+ "win_rate_pct": 100.0
117
+ },
118
+ {
119
+ "symbol": "CEG",
120
+ "trades": 1,
121
+ "pnl": 0.78,
122
+ "wins": 1,
123
+ "win_rate_pct": 100.0
124
+ },
125
+ {
126
+ "symbol": "AVGO",
127
+ "trades": 1,
128
+ "pnl": 0.6,
129
+ "wins": 1,
130
+ "win_rate_pct": 100.0
131
+ },
132
+ {
133
+ "symbol": "KLAC",
134
+ "trades": 1,
135
+ "pnl": 0.53,
136
+ "wins": 1,
137
+ "win_rate_pct": 100.0
138
+ },
139
+ {
140
+ "symbol": "TXN",
141
+ "trades": 2,
142
+ "pnl": 0.5,
143
+ "wins": 1,
144
+ "win_rate_pct": 50.0
145
+ },
146
+ {
147
+ "symbol": "SHOP",
148
+ "trades": 1,
149
+ "pnl": 0.46,
150
+ "wins": 1,
151
+ "win_rate_pct": 100.0
152
+ },
153
+ {
154
+ "symbol": "MCHP",
155
+ "trades": 1,
156
+ "pnl": 0.12,
157
+ "wins": 1,
158
+ "win_rate_pct": 100.0
159
+ },
160
+ {
161
+ "symbol": "PYPL",
162
+ "trades": 1,
163
+ "pnl": 0.11,
164
+ "wins": 1,
165
+ "win_rate_pct": 100.0
166
+ },
167
+ {
168
+ "symbol": "WDC",
169
+ "trades": 1,
170
+ "pnl": 0.04,
171
+ "wins": 1,
172
+ "win_rate_pct": 100.0
173
+ },
174
+ {
175
+ "symbol": "XEL",
176
+ "trades": 1,
177
+ "pnl": -0.1,
178
+ "wins": 0,
179
+ "win_rate_pct": 0.0
180
+ },
181
+ {
182
+ "symbol": "BKR",
183
+ "trades": 1,
184
+ "pnl": -0.14,
185
+ "wins": 0,
186
+ "win_rate_pct": 0.0
187
+ },
188
+ {
189
+ "symbol": "TRI",
190
+ "trades": 1,
191
+ "pnl": -0.38,
192
+ "wins": 0,
193
+ "win_rate_pct": 0.0
194
+ },
195
+ {
196
+ "symbol": "INTC",
197
+ "trades": 2,
198
+ "pnl": -0.7,
199
+ "wins": 0,
200
+ "win_rate_pct": 0.0
201
+ },
202
+ {
203
+ "symbol": "CRWV",
204
+ "trades": 2,
205
+ "pnl": -0.84,
206
+ "wins": 0,
207
+ "win_rate_pct": 0.0
208
+ },
209
+ {
210
+ "symbol": "NXPI",
211
+ "trades": 1,
212
+ "pnl": -0.94,
213
+ "wins": 0,
214
+ "win_rate_pct": 0.0
215
+ },
216
+ {
217
+ "symbol": "ARM",
218
+ "trades": 1,
219
+ "pnl": -1.61,
220
+ "wins": 0,
221
+ "win_rate_pct": 0.0
222
+ },
223
+ {
224
+ "symbol": "SPCX",
225
+ "trades": 3,
226
+ "pnl": -2.2,
227
+ "wins": 0,
228
+ "win_rate_pct": 0.0
229
+ }
230
+ ],
231
+ "per_exit_reason": [
232
+ {
233
+ "exit_reason": "model_exit",
234
+ "trades": 15,
235
+ "pnl": 24.01,
236
+ "wins": 14,
237
+ "win_rate_pct": 93.3
238
+ },
239
+ {
240
+ "exit_reason": "take_profit",
241
+ "trades": 8,
242
+ "pnl": 10.06,
243
+ "wins": 8,
244
+ "win_rate_pct": 100.0
245
+ },
246
+ {
247
+ "exit_reason": "stop_loss",
248
+ "trades": 12,
249
+ "pnl": -7.57,
250
+ "wins": 0,
251
+ "win_rate_pct": 0.0
252
+ }
253
+ ]
254
+ }
stockpilot/data/reports/wf_entry90_f3_20261020_110648.json ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "wf_entry90_f3",
3
+ "generated_at": "2026-10-20T11:06:48.368596+00:00",
4
+ "start": "2026-10-08T13:30:00+00:00",
5
+ "end": "2026-10-19T20:00:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 625,
8
+ "model": {
9
+ "rows": 248377,
10
+ "bottom_positive": 6368,
11
+ "top_positive": 6500,
12
+ "bottom_auc": 0.9187211874528274,
13
+ "top_auc": 0.9179580708694597,
14
+ "bottom_cv_auc": 0.8875960778783734,
15
+ "top_cv_auc": 0.8892319536314784,
16
+ "trained_at": "2026-10-20T11:03:46.014204+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.9,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 9999.58,
32
+ "total_return_pct": -0.004,
33
+ "max_drawdown_pct": -0.079,
34
+ "sharpe_daily_annualized": -2.861,
35
+ "trades": 32,
36
+ "win_rate_pct": 50.0,
37
+ "profit_factor": 1.004,
38
+ "avg_trade_pnl": 0.0014,
39
+ "avg_win": 0.8199,
40
+ "avg_loss": -0.817,
41
+ "gross_profit": 13.12,
42
+ "gross_loss": 13.07,
43
+ "exposure_pct": 23.68,
44
+ "bars": 625,
45
+ "days": 8
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "MRNA",
50
+ "trades": 1,
51
+ "pnl": 2.62,
52
+ "wins": 1,
53
+ "win_rate_pct": 100.0
54
+ },
55
+ {
56
+ "symbol": "ADBE",
57
+ "trades": 1,
58
+ "pnl": 2.2,
59
+ "wins": 1,
60
+ "win_rate_pct": 100.0
61
+ },
62
+ {
63
+ "symbol": "INTU",
64
+ "trades": 1,
65
+ "pnl": 1.61,
66
+ "wins": 1,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "KLAC",
71
+ "trades": 1,
72
+ "pnl": 1.55,
73
+ "wins": 1,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "MAR",
78
+ "trades": 1,
79
+ "pnl": 0.68,
80
+ "wins": 1,
81
+ "win_rate_pct": 100.0
82
+ },
83
+ {
84
+ "symbol": "HONA",
85
+ "trades": 3,
86
+ "pnl": 0.67,
87
+ "wins": 2,
88
+ "win_rate_pct": 66.7
89
+ },
90
+ {
91
+ "symbol": "TRI",
92
+ "trades": 1,
93
+ "pnl": 0.62,
94
+ "wins": 1,
95
+ "win_rate_pct": 100.0
96
+ },
97
+ {
98
+ "symbol": "CTAS",
99
+ "trades": 1,
100
+ "pnl": 0.41,
101
+ "wins": 1,
102
+ "win_rate_pct": 100.0
103
+ },
104
+ {
105
+ "symbol": "DDOG",
106
+ "trades": 2,
107
+ "pnl": 0.32,
108
+ "wins": 1,
109
+ "win_rate_pct": 50.0
110
+ },
111
+ {
112
+ "symbol": "GEHC",
113
+ "trades": 2,
114
+ "pnl": 0.24,
115
+ "wins": 2,
116
+ "win_rate_pct": 100.0
117
+ },
118
+ {
119
+ "symbol": "FAST",
120
+ "trades": 1,
121
+ "pnl": 0.18,
122
+ "wins": 1,
123
+ "win_rate_pct": 100.0
124
+ },
125
+ {
126
+ "symbol": "KDP",
127
+ "trades": 1,
128
+ "pnl": 0.12,
129
+ "wins": 1,
130
+ "win_rate_pct": 100.0
131
+ },
132
+ {
133
+ "symbol": "MNST",
134
+ "trades": 1,
135
+ "pnl": 0.07,
136
+ "wins": 1,
137
+ "win_rate_pct": 100.0
138
+ },
139
+ {
140
+ "symbol": "BKR",
141
+ "trades": 1,
142
+ "pnl": -0.01,
143
+ "wins": 0,
144
+ "win_rate_pct": 0.0
145
+ },
146
+ {
147
+ "symbol": "PDD",
148
+ "trades": 2,
149
+ "pnl": -0.06,
150
+ "wins": 1,
151
+ "win_rate_pct": 50.0
152
+ },
153
+ {
154
+ "symbol": "ODFL",
155
+ "trades": 1,
156
+ "pnl": -0.14,
157
+ "wins": 0,
158
+ "win_rate_pct": 0.0
159
+ },
160
+ {
161
+ "symbol": "WMT",
162
+ "trades": 1,
163
+ "pnl": -0.17,
164
+ "wins": 0,
165
+ "win_rate_pct": 0.0
166
+ },
167
+ {
168
+ "symbol": "CCEP",
169
+ "trades": 1,
170
+ "pnl": -0.28,
171
+ "wins": 0,
172
+ "win_rate_pct": 0.0
173
+ },
174
+ {
175
+ "symbol": "ROST",
176
+ "trades": 1,
177
+ "pnl": -0.37,
178
+ "wins": 0,
179
+ "win_rate_pct": 0.0
180
+ },
181
+ {
182
+ "symbol": "DASH",
183
+ "trades": 1,
184
+ "pnl": -0.65,
185
+ "wins": 0,
186
+ "win_rate_pct": 0.0
187
+ },
188
+ {
189
+ "symbol": "NXPI",
190
+ "trades": 1,
191
+ "pnl": -0.88,
192
+ "wins": 0,
193
+ "win_rate_pct": 0.0
194
+ },
195
+ {
196
+ "symbol": "ISRG",
197
+ "trades": 2,
198
+ "pnl": -1.23,
199
+ "wins": 0,
200
+ "win_rate_pct": 0.0
201
+ },
202
+ {
203
+ "symbol": "APP",
204
+ "trades": 1,
205
+ "pnl": -1.4,
206
+ "wins": 0,
207
+ "win_rate_pct": 0.0
208
+ },
209
+ {
210
+ "symbol": "MRVL",
211
+ "trades": 1,
212
+ "pnl": -1.46,
213
+ "wins": 0,
214
+ "win_rate_pct": 0.0
215
+ },
216
+ {
217
+ "symbol": "REGN",
218
+ "trades": 2,
219
+ "pnl": -4.6,
220
+ "wins": 0,
221
+ "win_rate_pct": 0.0
222
+ }
223
+ ],
224
+ "per_exit_reason": [
225
+ {
226
+ "exit_reason": "model_exit",
227
+ "trades": 13,
228
+ "pnl": 8.32,
229
+ "wins": 10,
230
+ "win_rate_pct": 76.9
231
+ },
232
+ {
233
+ "exit_reason": "take_profit",
234
+ "trades": 6,
235
+ "pnl": 4.63,
236
+ "wins": 6,
237
+ "win_rate_pct": 100.0
238
+ },
239
+ {
240
+ "exit_reason": "stop_loss",
241
+ "trades": 13,
242
+ "pnl": -12.91,
243
+ "wins": 0,
244
+ "win_rate_pct": 0.0
245
+ }
246
+ ]
247
+ }
stockpilot/data/reports/wf_entry90_walkforward_20261020_110648.json ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "aggregate": {
3
+ "label": "wf_entry90",
4
+ "folds": 3,
5
+ "compounded_return_pct": 0.351,
6
+ "mean_fold_return_pct": 0.117,
7
+ "positive_folds": 2,
8
+ "trades": 118,
9
+ "win_rate_pct": 59.33,
10
+ "profit_factor": 4.087,
11
+ "worst_drawdown_pct": -0.129,
12
+ "initial_cash": 10000.0
13
+ },
14
+ "folds": [
15
+ {
16
+ "fold": 1,
17
+ "start": "2026-09-16T13:30:00+00:00",
18
+ "end": "2026-09-25T19:55:00+00:00",
19
+ "metrics": {
20
+ "initial_cash": 10000.0,
21
+ "final_equity": 10021.49,
22
+ "total_return_pct": 0.215,
23
+ "max_drawdown_pct": -0.129,
24
+ "sharpe_daily_annualized": 9.582,
25
+ "trades": 51,
26
+ "win_rate_pct": 62.75,
27
+ "profit_factor": 5.814,
28
+ "avg_trade_pnl": 2.0328,
29
+ "avg_win": 3.9127,
30
+ "avg_loss": -1.1334,
31
+ "gross_profit": 125.21,
32
+ "gross_loss": 21.53,
33
+ "exposure_pct": 30.45,
34
+ "bars": 624,
35
+ "days": 8
36
+ },
37
+ "report_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/reports/wf_entry90_f1_20261020_105952.json",
38
+ "store_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/backtests/wf_entry90_f1_20261020_105936.db"
39
+ },
40
+ {
41
+ "fold": 2,
42
+ "start": "2026-09-28T13:30:00+00:00",
43
+ "end": "2026-10-07T19:55:00+00:00",
44
+ "metrics": {
45
+ "initial_cash": 10000.0,
46
+ "final_equity": 10013.96,
47
+ "total_return_pct": 0.14,
48
+ "max_drawdown_pct": -0.043,
49
+ "sharpe_daily_annualized": 8.838,
50
+ "trades": 35,
51
+ "win_rate_pct": 62.86,
52
+ "profit_factor": 4.49,
53
+ "avg_trade_pnl": 0.7573,
54
+ "avg_win": 1.5501,
55
+ "avg_loss": -0.5842,
56
+ "gross_profit": 34.1,
57
+ "gross_loss": 7.59,
58
+ "exposure_pct": 15.06,
59
+ "bars": 624,
60
+ "days": 8
61
+ },
62
+ "report_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/reports/wf_entry90_f2_20261020_110319.json",
63
+ "store_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/backtests/wf_entry90_f2_20261020_110253.db"
64
+ },
65
+ {
66
+ "fold": 3,
67
+ "start": "2026-10-08T13:30:00+00:00",
68
+ "end": "2026-10-19T20:00:00+00:00",
69
+ "metrics": {
70
+ "initial_cash": 10000.0,
71
+ "final_equity": 9999.58,
72
+ "total_return_pct": -0.004,
73
+ "max_drawdown_pct": -0.079,
74
+ "sharpe_daily_annualized": -2.861,
75
+ "trades": 32,
76
+ "win_rate_pct": 50.0,
77
+ "profit_factor": 1.004,
78
+ "avg_trade_pnl": 0.0014,
79
+ "avg_win": 0.8199,
80
+ "avg_loss": -0.817,
81
+ "gross_profit": 13.12,
82
+ "gross_loss": 13.07,
83
+ "exposure_pct": 23.68,
84
+ "bars": 625,
85
+ "days": 8
86
+ },
87
+ "report_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/reports/wf_entry90_f3_20261020_110648.json",
88
+ "store_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/backtests/wf_entry90_f3_20261020_110626.db"
89
+ }
90
+ ]
91
+ }
stockpilot/data/reports/wf_stop12_f1_20261020_105953.json ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "wf_stop12_f1",
3
+ "generated_at": "2026-10-20T10:59:53.325106+00:00",
4
+ "start": "2026-09-16T13:30:00+00:00",
5
+ "end": "2026-09-25T19:55:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 624,
8
+ "model": {
9
+ "rows": 123588,
10
+ "bottom_positive": 3097,
11
+ "top_positive": 3320,
12
+ "bottom_auc": 0.9286175360617559,
13
+ "top_auc": 0.929439890970407,
14
+ "bottom_cv_auc": 0.8762567127509834,
15
+ "top_cv_auc": 0.8843654091667135,
16
+ "trained_at": "2026-10-20T10:58:08.525384+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.85,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 10037.4,
32
+ "total_return_pct": 0.374,
33
+ "max_drawdown_pct": -0.16,
34
+ "sharpe_daily_annualized": 9.223,
35
+ "trades": 150,
36
+ "win_rate_pct": 66.0,
37
+ "profit_factor": 3.104,
38
+ "avg_trade_pnl": 0.9209,
39
+ "avg_win": 2.0586,
40
+ "avg_loss": -1.2876,
41
+ "gross_profit": 203.8,
42
+ "gross_loss": 65.67,
43
+ "exposure_pct": 55.61,
44
+ "bars": 624,
45
+ "days": 8
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "ALAB",
50
+ "trades": 8,
51
+ "pnl": 105.98,
52
+ "wins": 7,
53
+ "win_rate_pct": 87.5
54
+ },
55
+ {
56
+ "symbol": "STX",
57
+ "trades": 2,
58
+ "pnl": 9.9,
59
+ "wins": 2,
60
+ "win_rate_pct": 100.0
61
+ },
62
+ {
63
+ "symbol": "META",
64
+ "trades": 1,
65
+ "pnl": 5.47,
66
+ "wins": 1,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "SNPS",
71
+ "trades": 3,
72
+ "pnl": 5.46,
73
+ "wins": 3,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "LRCX",
78
+ "trades": 5,
79
+ "pnl": 4.67,
80
+ "wins": 5,
81
+ "win_rate_pct": 100.0
82
+ },
83
+ {
84
+ "symbol": "AMD",
85
+ "trades": 2,
86
+ "pnl": 4.57,
87
+ "wins": 2,
88
+ "win_rate_pct": 100.0
89
+ },
90
+ {
91
+ "symbol": "ALNY",
92
+ "trades": 4,
93
+ "pnl": 3.77,
94
+ "wins": 3,
95
+ "win_rate_pct": 75.0
96
+ },
97
+ {
98
+ "symbol": "CDNS",
99
+ "trades": 3,
100
+ "pnl": 2.57,
101
+ "wins": 3,
102
+ "win_rate_pct": 100.0
103
+ },
104
+ {
105
+ "symbol": "WDC",
106
+ "trades": 2,
107
+ "pnl": 2.21,
108
+ "wins": 1,
109
+ "win_rate_pct": 50.0
110
+ },
111
+ {
112
+ "symbol": "ADI",
113
+ "trades": 3,
114
+ "pnl": 2.17,
115
+ "wins": 2,
116
+ "win_rate_pct": 66.7
117
+ },
118
+ {
119
+ "symbol": "HONA",
120
+ "trades": 2,
121
+ "pnl": 1.83,
122
+ "wins": 2,
123
+ "win_rate_pct": 100.0
124
+ },
125
+ {
126
+ "symbol": "NBIS",
127
+ "trades": 7,
128
+ "pnl": 1.58,
129
+ "wins": 5,
130
+ "win_rate_pct": 71.4
131
+ },
132
+ {
133
+ "symbol": "AMAT",
134
+ "trades": 2,
135
+ "pnl": 1.41,
136
+ "wins": 1,
137
+ "win_rate_pct": 50.0
138
+ },
139
+ {
140
+ "symbol": "NXPI",
141
+ "trades": 1,
142
+ "pnl": 1.22,
143
+ "wins": 1,
144
+ "win_rate_pct": 100.0
145
+ },
146
+ {
147
+ "symbol": "ARM",
148
+ "trades": 5,
149
+ "pnl": 1.14,
150
+ "wins": 3,
151
+ "win_rate_pct": 60.0
152
+ },
153
+ {
154
+ "symbol": "WDAY",
155
+ "trades": 1,
156
+ "pnl": 1.12,
157
+ "wins": 1,
158
+ "win_rate_pct": 100.0
159
+ },
160
+ {
161
+ "symbol": "TXN",
162
+ "trades": 1,
163
+ "pnl": 0.98,
164
+ "wins": 1,
165
+ "win_rate_pct": 100.0
166
+ },
167
+ {
168
+ "symbol": "MRVL",
169
+ "trades": 5,
170
+ "pnl": 0.9,
171
+ "wins": 3,
172
+ "win_rate_pct": 60.0
173
+ },
174
+ {
175
+ "symbol": "CEG",
176
+ "trades": 1,
177
+ "pnl": 0.73,
178
+ "wins": 1,
179
+ "win_rate_pct": 100.0
180
+ },
181
+ {
182
+ "symbol": "FTNT",
183
+ "trades": 4,
184
+ "pnl": 0.59,
185
+ "wins": 3,
186
+ "win_rate_pct": 75.0
187
+ },
188
+ {
189
+ "symbol": "HON",
190
+ "trades": 2,
191
+ "pnl": 0.58,
192
+ "wins": 2,
193
+ "win_rate_pct": 100.0
194
+ },
195
+ {
196
+ "symbol": "TRI",
197
+ "trades": 2,
198
+ "pnl": 0.51,
199
+ "wins": 2,
200
+ "win_rate_pct": 100.0
201
+ },
202
+ {
203
+ "symbol": "CRWD",
204
+ "trades": 4,
205
+ "pnl": 0.5,
206
+ "wins": 3,
207
+ "win_rate_pct": 75.0
208
+ },
209
+ {
210
+ "symbol": "ROST",
211
+ "trades": 1,
212
+ "pnl": 0.49,
213
+ "wins": 1,
214
+ "win_rate_pct": 100.0
215
+ },
216
+ {
217
+ "symbol": "GOOGL",
218
+ "trades": 1,
219
+ "pnl": 0.49,
220
+ "wins": 1,
221
+ "win_rate_pct": 100.0
222
+ },
223
+ {
224
+ "symbol": "BKR",
225
+ "trades": 2,
226
+ "pnl": 0.4,
227
+ "wins": 2,
228
+ "win_rate_pct": 100.0
229
+ },
230
+ {
231
+ "symbol": "QCOM",
232
+ "trades": 1,
233
+ "pnl": 0.39,
234
+ "wins": 1,
235
+ "win_rate_pct": 100.0
236
+ },
237
+ {
238
+ "symbol": "BKNG",
239
+ "trades": 1,
240
+ "pnl": 0.38,
241
+ "wins": 1,
242
+ "win_rate_pct": 100.0
243
+ },
244
+ {
245
+ "symbol": "MSTR",
246
+ "trades": 1,
247
+ "pnl": 0.23,
248
+ "wins": 1,
249
+ "win_rate_pct": 100.0
250
+ },
251
+ {
252
+ "symbol": "DXCM",
253
+ "trades": 3,
254
+ "pnl": 0.22,
255
+ "wins": 2,
256
+ "win_rate_pct": 66.7
257
+ },
258
+ {
259
+ "symbol": "TER",
260
+ "trades": 7,
261
+ "pnl": 0.18,
262
+ "wins": 5,
263
+ "win_rate_pct": 71.4
264
+ },
265
+ {
266
+ "symbol": "PDD",
267
+ "trades": 1,
268
+ "pnl": 0.17,
269
+ "wins": 1,
270
+ "win_rate_pct": 100.0
271
+ },
272
+ {
273
+ "symbol": "FAST",
274
+ "trades": 1,
275
+ "pnl": 0.16,
276
+ "wins": 1,
277
+ "win_rate_pct": 100.0
278
+ },
279
+ {
280
+ "symbol": "GILD",
281
+ "trades": 1,
282
+ "pnl": 0.15,
283
+ "wins": 1,
284
+ "win_rate_pct": 100.0
285
+ },
286
+ {
287
+ "symbol": "AMZN",
288
+ "trades": 2,
289
+ "pnl": 0.11,
290
+ "wins": 1,
291
+ "win_rate_pct": 50.0
292
+ },
293
+ {
294
+ "symbol": "ORLY",
295
+ "trades": 2,
296
+ "pnl": 0.04,
297
+ "wins": 1,
298
+ "win_rate_pct": 50.0
299
+ },
300
+ {
301
+ "symbol": "MRNA",
302
+ "trades": 10,
303
+ "pnl": -0.01,
304
+ "wins": 5,
305
+ "win_rate_pct": 50.0
306
+ },
307
+ {
308
+ "symbol": "GEHC",
309
+ "trades": 1,
310
+ "pnl": -0.07,
311
+ "wins": 0,
312
+ "win_rate_pct": 0.0
313
+ },
314
+ {
315
+ "symbol": "IDXX",
316
+ "trades": 2,
317
+ "pnl": -0.17,
318
+ "wins": 1,
319
+ "win_rate_pct": 50.0
320
+ },
321
+ {
322
+ "symbol": "MCHP",
323
+ "trades": 4,
324
+ "pnl": -0.25,
325
+ "wins": 2,
326
+ "win_rate_pct": 50.0
327
+ },
328
+ {
329
+ "symbol": "PYPL",
330
+ "trades": 1,
331
+ "pnl": -0.26,
332
+ "wins": 0,
333
+ "win_rate_pct": 0.0
334
+ },
335
+ {
336
+ "symbol": "INTC",
337
+ "trades": 3,
338
+ "pnl": -0.27,
339
+ "wins": 2,
340
+ "win_rate_pct": 66.7
341
+ },
342
+ {
343
+ "symbol": "SPCX",
344
+ "trades": 2,
345
+ "pnl": -0.36,
346
+ "wins": 1,
347
+ "win_rate_pct": 50.0
348
+ },
349
+ {
350
+ "symbol": "PLTR",
351
+ "trades": 4,
352
+ "pnl": -0.4,
353
+ "wins": 3,
354
+ "win_rate_pct": 75.0
355
+ },
356
+ {
357
+ "symbol": "CRWV",
358
+ "trades": 2,
359
+ "pnl": -0.47,
360
+ "wins": 1,
361
+ "win_rate_pct": 50.0
362
+ },
363
+ {
364
+ "symbol": "RKLB",
365
+ "trades": 5,
366
+ "pnl": -0.47,
367
+ "wins": 3,
368
+ "win_rate_pct": 60.0
369
+ },
370
+ {
371
+ "symbol": "AAPL",
372
+ "trades": 1,
373
+ "pnl": -0.77,
374
+ "wins": 0,
375
+ "win_rate_pct": 0.0
376
+ },
377
+ {
378
+ "symbol": "SHOP",
379
+ "trades": 1,
380
+ "pnl": -0.86,
381
+ "wins": 0,
382
+ "win_rate_pct": 0.0
383
+ },
384
+ {
385
+ "symbol": "KLAC",
386
+ "trades": 1,
387
+ "pnl": -0.86,
388
+ "wins": 0,
389
+ "win_rate_pct": 0.0
390
+ },
391
+ {
392
+ "symbol": "AVGO",
393
+ "trades": 1,
394
+ "pnl": -1.02,
395
+ "wins": 0,
396
+ "win_rate_pct": 0.0
397
+ },
398
+ {
399
+ "symbol": "ISRG",
400
+ "trades": 4,
401
+ "pnl": -1.16,
402
+ "wins": 1,
403
+ "win_rate_pct": 25.0
404
+ },
405
+ {
406
+ "symbol": "DDOG",
407
+ "trades": 6,
408
+ "pnl": -1.48,
409
+ "wins": 2,
410
+ "win_rate_pct": 33.3
411
+ },
412
+ {
413
+ "symbol": "TSLA",
414
+ "trades": 2,
415
+ "pnl": -2.08,
416
+ "wins": 0,
417
+ "win_rate_pct": 0.0
418
+ },
419
+ {
420
+ "symbol": "AMGN",
421
+ "trades": 1,
422
+ "pnl": -2.15,
423
+ "wins": 0,
424
+ "win_rate_pct": 0.0
425
+ },
426
+ {
427
+ "symbol": "PANW",
428
+ "trades": 3,
429
+ "pnl": -4.32,
430
+ "wins": 1,
431
+ "win_rate_pct": 33.3
432
+ },
433
+ {
434
+ "symbol": "LITE",
435
+ "trades": 2,
436
+ "pnl": -7.69,
437
+ "wins": 1,
438
+ "win_rate_pct": 50.0
439
+ }
440
+ ],
441
+ "per_exit_reason": [
442
+ {
443
+ "exit_reason": "model_exit",
444
+ "trades": 83,
445
+ "pnl": 113.48,
446
+ "wins": 78,
447
+ "win_rate_pct": 94.0
448
+ },
449
+ {
450
+ "exit_reason": "take_profit",
451
+ "trades": 18,
452
+ "pnl": 64.73,
453
+ "wins": 18,
454
+ "win_rate_pct": 100.0
455
+ },
456
+ {
457
+ "exit_reason": "flatten_all",
458
+ "trades": 1,
459
+ "pnl": -0.7,
460
+ "wins": 0,
461
+ "win_rate_pct": 0.0
462
+ },
463
+ {
464
+ "exit_reason": "stop_loss",
465
+ "trades": 48,
466
+ "pnl": -39.36,
467
+ "wins": 3,
468
+ "win_rate_pct": 6.2
469
+ }
470
+ ]
471
+ }
stockpilot/data/reports/wf_stop12_f2_20261020_110322.json ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "wf_stop12_f2",
3
+ "generated_at": "2026-10-20T11:03:22.235567+00:00",
4
+ "start": "2026-09-28T13:30:00+00:00",
5
+ "end": "2026-10-07T19:55:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 624,
8
+ "model": {
9
+ "rows": 185984,
10
+ "bottom_positive": 4719,
11
+ "top_positive": 4917,
12
+ "bottom_auc": 0.9222607206668713,
13
+ "top_auc": 0.9239758042455313,
14
+ "bottom_cv_auc": 0.8827475558726079,
15
+ "top_cv_auc": 0.8895076776138559,
16
+ "trained_at": "2026-10-20T11:00:53.236181+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.85,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 10026.21,
32
+ "total_return_pct": 0.262,
33
+ "max_drawdown_pct": -0.069,
34
+ "sharpe_daily_annualized": 9.962,
35
+ "trades": 114,
36
+ "win_rate_pct": 60.53,
37
+ "profit_factor": 1.613,
38
+ "avg_trade_pnl": 0.2908,
39
+ "avg_win": 1.2644,
40
+ "avg_loss": -1.202,
41
+ "gross_profit": 87.24,
42
+ "gross_loss": 54.09,
43
+ "exposure_pct": 42.15,
44
+ "bars": 624,
45
+ "days": 8
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "ALAB",
50
+ "trades": 5,
51
+ "pnl": 22.6,
52
+ "wins": 4,
53
+ "win_rate_pct": 80.0
54
+ },
55
+ {
56
+ "symbol": "TER",
57
+ "trades": 3,
58
+ "pnl": 4.7,
59
+ "wins": 3,
60
+ "win_rate_pct": 100.0
61
+ },
62
+ {
63
+ "symbol": "SNPS",
64
+ "trades": 1,
65
+ "pnl": 4.54,
66
+ "wins": 1,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "DDOG",
71
+ "trades": 4,
72
+ "pnl": 4.51,
73
+ "wins": 4,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "AMAT",
78
+ "trades": 2,
79
+ "pnl": 3.35,
80
+ "wins": 2,
81
+ "win_rate_pct": 100.0
82
+ },
83
+ {
84
+ "symbol": "KLAC",
85
+ "trades": 3,
86
+ "pnl": 2.4,
87
+ "wins": 3,
88
+ "win_rate_pct": 100.0
89
+ },
90
+ {
91
+ "symbol": "STX",
92
+ "trades": 1,
93
+ "pnl": 2.3,
94
+ "wins": 1,
95
+ "win_rate_pct": 100.0
96
+ },
97
+ {
98
+ "symbol": "AMD",
99
+ "trades": 1,
100
+ "pnl": 2.29,
101
+ "wins": 1,
102
+ "win_rate_pct": 100.0
103
+ },
104
+ {
105
+ "symbol": "MSTR",
106
+ "trades": 2,
107
+ "pnl": 2.23,
108
+ "wins": 2,
109
+ "win_rate_pct": 100.0
110
+ },
111
+ {
112
+ "symbol": "TXN",
113
+ "trades": 4,
114
+ "pnl": 2.23,
115
+ "wins": 3,
116
+ "win_rate_pct": 75.0
117
+ },
118
+ {
119
+ "symbol": "LRCX",
120
+ "trades": 3,
121
+ "pnl": 1.61,
122
+ "wins": 2,
123
+ "win_rate_pct": 66.7
124
+ },
125
+ {
126
+ "symbol": "SHOP",
127
+ "trades": 3,
128
+ "pnl": 1.5,
129
+ "wins": 3,
130
+ "win_rate_pct": 100.0
131
+ },
132
+ {
133
+ "symbol": "TSLA",
134
+ "trades": 1,
135
+ "pnl": 1.46,
136
+ "wins": 1,
137
+ "win_rate_pct": 100.0
138
+ },
139
+ {
140
+ "symbol": "NBIS",
141
+ "trades": 5,
142
+ "pnl": 1.36,
143
+ "wins": 3,
144
+ "win_rate_pct": 60.0
145
+ },
146
+ {
147
+ "symbol": "ISRG",
148
+ "trades": 2,
149
+ "pnl": 1.31,
150
+ "wins": 2,
151
+ "win_rate_pct": 100.0
152
+ },
153
+ {
154
+ "symbol": "CDNS",
155
+ "trades": 4,
156
+ "pnl": 1.28,
157
+ "wins": 3,
158
+ "win_rate_pct": 75.0
159
+ },
160
+ {
161
+ "symbol": "DASH",
162
+ "trades": 1,
163
+ "pnl": 0.92,
164
+ "wins": 1,
165
+ "win_rate_pct": 100.0
166
+ },
167
+ {
168
+ "symbol": "META",
169
+ "trades": 1,
170
+ "pnl": 0.86,
171
+ "wins": 1,
172
+ "win_rate_pct": 100.0
173
+ },
174
+ {
175
+ "symbol": "PANW",
176
+ "trades": 3,
177
+ "pnl": 0.86,
178
+ "wins": 2,
179
+ "win_rate_pct": 66.7
180
+ },
181
+ {
182
+ "symbol": "HON",
183
+ "trades": 1,
184
+ "pnl": 0.67,
185
+ "wins": 1,
186
+ "win_rate_pct": 100.0
187
+ },
188
+ {
189
+ "symbol": "ADI",
190
+ "trades": 3,
191
+ "pnl": 0.63,
192
+ "wins": 2,
193
+ "win_rate_pct": 66.7
194
+ },
195
+ {
196
+ "symbol": "GILD",
197
+ "trades": 1,
198
+ "pnl": 0.39,
199
+ "wins": 1,
200
+ "win_rate_pct": 100.0
201
+ },
202
+ {
203
+ "symbol": "CSCO",
204
+ "trades": 1,
205
+ "pnl": 0.36,
206
+ "wins": 1,
207
+ "win_rate_pct": 100.0
208
+ },
209
+ {
210
+ "symbol": "LIN",
211
+ "trades": 2,
212
+ "pnl": 0.26,
213
+ "wins": 1,
214
+ "win_rate_pct": 50.0
215
+ },
216
+ {
217
+ "symbol": "NXPI",
218
+ "trades": 2,
219
+ "pnl": 0.25,
220
+ "wins": 1,
221
+ "win_rate_pct": 50.0
222
+ },
223
+ {
224
+ "symbol": "XEL",
225
+ "trades": 3,
226
+ "pnl": 0.14,
227
+ "wins": 2,
228
+ "win_rate_pct": 66.7
229
+ },
230
+ {
231
+ "symbol": "PYPL",
232
+ "trades": 1,
233
+ "pnl": 0.11,
234
+ "wins": 1,
235
+ "win_rate_pct": 100.0
236
+ },
237
+ {
238
+ "symbol": "ODFL",
239
+ "trades": 2,
240
+ "pnl": 0.05,
241
+ "wins": 1,
242
+ "win_rate_pct": 50.0
243
+ },
244
+ {
245
+ "symbol": "ABNB",
246
+ "trades": 3,
247
+ "pnl": 0.04,
248
+ "wins": 2,
249
+ "win_rate_pct": 66.7
250
+ },
251
+ {
252
+ "symbol": "WDC",
253
+ "trades": 1,
254
+ "pnl": 0.04,
255
+ "wins": 1,
256
+ "win_rate_pct": 100.0
257
+ },
258
+ {
259
+ "symbol": "ORLY",
260
+ "trades": 1,
261
+ "pnl": 0.01,
262
+ "wins": 1,
263
+ "win_rate_pct": 100.0
264
+ },
265
+ {
266
+ "symbol": "SBUX",
267
+ "trades": 1,
268
+ "pnl": 0.0,
269
+ "wins": 1,
270
+ "win_rate_pct": 100.0
271
+ },
272
+ {
273
+ "symbol": "HONA",
274
+ "trades": 1,
275
+ "pnl": -0.03,
276
+ "wins": 0,
277
+ "win_rate_pct": 0.0
278
+ },
279
+ {
280
+ "symbol": "CPRT",
281
+ "trades": 1,
282
+ "pnl": -0.08,
283
+ "wins": 0,
284
+ "win_rate_pct": 0.0
285
+ },
286
+ {
287
+ "symbol": "BKR",
288
+ "trades": 2,
289
+ "pnl": -0.12,
290
+ "wins": 1,
291
+ "win_rate_pct": 50.0
292
+ },
293
+ {
294
+ "symbol": "INTC",
295
+ "trades": 3,
296
+ "pnl": -0.19,
297
+ "wins": 1,
298
+ "win_rate_pct": 33.3
299
+ },
300
+ {
301
+ "symbol": "MCHP",
302
+ "trades": 3,
303
+ "pnl": -0.43,
304
+ "wins": 1,
305
+ "win_rate_pct": 33.3
306
+ },
307
+ {
308
+ "symbol": "CRWV",
309
+ "trades": 3,
310
+ "pnl": -0.47,
311
+ "wins": 1,
312
+ "win_rate_pct": 33.3
313
+ },
314
+ {
315
+ "symbol": "MRNA",
316
+ "trades": 2,
317
+ "pnl": -0.5,
318
+ "wins": 1,
319
+ "win_rate_pct": 50.0
320
+ },
321
+ {
322
+ "symbol": "TRI",
323
+ "trades": 2,
324
+ "pnl": -0.51,
325
+ "wins": 0,
326
+ "win_rate_pct": 0.0
327
+ },
328
+ {
329
+ "symbol": "BKNG",
330
+ "trades": 2,
331
+ "pnl": -0.64,
332
+ "wins": 1,
333
+ "win_rate_pct": 50.0
334
+ },
335
+ {
336
+ "symbol": "TTWO",
337
+ "trades": 1,
338
+ "pnl": -0.64,
339
+ "wins": 0,
340
+ "win_rate_pct": 0.0
341
+ },
342
+ {
343
+ "symbol": "NVDA",
344
+ "trades": 1,
345
+ "pnl": -0.72,
346
+ "wins": 0,
347
+ "win_rate_pct": 0.0
348
+ },
349
+ {
350
+ "symbol": "WDAY",
351
+ "trades": 1,
352
+ "pnl": -0.88,
353
+ "wins": 0,
354
+ "win_rate_pct": 0.0
355
+ },
356
+ {
357
+ "symbol": "CRWD",
358
+ "trades": 5,
359
+ "pnl": -0.93,
360
+ "wins": 3,
361
+ "win_rate_pct": 60.0
362
+ },
363
+ {
364
+ "symbol": "AVGO",
365
+ "trades": 2,
366
+ "pnl": -0.94,
367
+ "wins": 1,
368
+ "win_rate_pct": 50.0
369
+ },
370
+ {
371
+ "symbol": "APP",
372
+ "trades": 1,
373
+ "pnl": -1.09,
374
+ "wins": 0,
375
+ "win_rate_pct": 0.0
376
+ },
377
+ {
378
+ "symbol": "RKLB",
379
+ "trades": 2,
380
+ "pnl": -1.1,
381
+ "wins": 0,
382
+ "win_rate_pct": 0.0
383
+ },
384
+ {
385
+ "symbol": "MSFT",
386
+ "trades": 1,
387
+ "pnl": -1.52,
388
+ "wins": 0,
389
+ "win_rate_pct": 0.0
390
+ },
391
+ {
392
+ "symbol": "ARM",
393
+ "trades": 1,
394
+ "pnl": -1.89,
395
+ "wins": 0,
396
+ "win_rate_pct": 0.0
397
+ },
398
+ {
399
+ "symbol": "CEG",
400
+ "trades": 2,
401
+ "pnl": -3.32,
402
+ "wins": 0,
403
+ "win_rate_pct": 0.0
404
+ },
405
+ {
406
+ "symbol": "SPCX",
407
+ "trades": 5,
408
+ "pnl": -3.9,
409
+ "wins": 0,
410
+ "win_rate_pct": 0.0
411
+ },
412
+ {
413
+ "symbol": "ALNY",
414
+ "trades": 2,
415
+ "pnl": -12.18,
416
+ "wins": 1,
417
+ "win_rate_pct": 50.0
418
+ }
419
+ ],
420
+ "per_exit_reason": [
421
+ {
422
+ "exit_reason": "take_profit",
423
+ "trades": 28,
424
+ "pnl": 46.89,
425
+ "wins": 28,
426
+ "win_rate_pct": 100.0
427
+ },
428
+ {
429
+ "exit_reason": "model_exit",
430
+ "trades": 44,
431
+ "pnl": 27.77,
432
+ "wins": 41,
433
+ "win_rate_pct": 93.2
434
+ },
435
+ {
436
+ "exit_reason": "flatten_all",
437
+ "trades": 1,
438
+ "pnl": -0.06,
439
+ "wins": 0,
440
+ "win_rate_pct": 0.0
441
+ },
442
+ {
443
+ "exit_reason": "stop_loss",
444
+ "trades": 41,
445
+ "pnl": -41.44,
446
+ "wins": 0,
447
+ "win_rate_pct": 0.0
448
+ }
449
+ ]
450
+ }
stockpilot/data/reports/wf_stop12_f3_20261020_110650.json ADDED
@@ -0,0 +1,443 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "label": "wf_stop12_f3",
3
+ "generated_at": "2026-10-20T11:06:50.658283+00:00",
4
+ "start": "2026-10-08T13:30:00+00:00",
5
+ "end": "2026-10-19T20:00:00+00:00",
6
+ "symbols": 100,
7
+ "bars": 625,
8
+ "model": {
9
+ "rows": 248377,
10
+ "bottom_positive": 6368,
11
+ "top_positive": 6500,
12
+ "bottom_auc": 0.9187211874528274,
13
+ "top_auc": 0.9179580708694597,
14
+ "bottom_cv_auc": 0.8875960778783734,
15
+ "top_cv_auc": 0.8892319536314784,
16
+ "trained_at": "2026-10-20T11:03:49.036566+00:00"
17
+ },
18
+ "settings": {
19
+ "entry_threshold": 0.85,
20
+ "exit_threshold": 0.55,
21
+ "initial_cash": 10000.0,
22
+ "cash_buffer_pct": 25.0,
23
+ "max_position_pct": 10.0,
24
+ "daily_loss_pct": 2.0,
25
+ "max_concurrent": 10,
26
+ "min_breadth": 0.0,
27
+ "slippage_bps": 2.0
28
+ },
29
+ "metrics": {
30
+ "initial_cash": 10000.0,
31
+ "final_equity": 9998.36,
32
+ "total_return_pct": -0.016,
33
+ "max_drawdown_pct": -0.104,
34
+ "sharpe_daily_annualized": -3.035,
35
+ "trades": 92,
36
+ "win_rate_pct": 55.43,
37
+ "profit_factor": 1.008,
38
+ "avg_trade_pnl": 0.0029,
39
+ "avg_win": 0.6607,
40
+ "avg_loss": -0.8155,
41
+ "gross_profit": 33.7,
42
+ "gross_loss": 33.43,
43
+ "exposure_pct": 47.84,
44
+ "bars": 625,
45
+ "days": 8
46
+ },
47
+ "per_symbol": [
48
+ {
49
+ "symbol": "ADI",
50
+ "trades": 2,
51
+ "pnl": 2.75,
52
+ "wins": 2,
53
+ "win_rate_pct": 100.0
54
+ },
55
+ {
56
+ "symbol": "CEG",
57
+ "trades": 2,
58
+ "pnl": 2.47,
59
+ "wins": 2,
60
+ "win_rate_pct": 100.0
61
+ },
62
+ {
63
+ "symbol": "AXON",
64
+ "trades": 1,
65
+ "pnl": 2.1,
66
+ "wins": 1,
67
+ "win_rate_pct": 100.0
68
+ },
69
+ {
70
+ "symbol": "KLAC",
71
+ "trades": 1,
72
+ "pnl": 1.55,
73
+ "wins": 1,
74
+ "win_rate_pct": 100.0
75
+ },
76
+ {
77
+ "symbol": "FANG",
78
+ "trades": 2,
79
+ "pnl": 1.38,
80
+ "wins": 2,
81
+ "win_rate_pct": 100.0
82
+ },
83
+ {
84
+ "symbol": "ALNY",
85
+ "trades": 1,
86
+ "pnl": 1.32,
87
+ "wins": 1,
88
+ "win_rate_pct": 100.0
89
+ },
90
+ {
91
+ "symbol": "WDAY",
92
+ "trades": 2,
93
+ "pnl": 1.19,
94
+ "wins": 2,
95
+ "win_rate_pct": 100.0
96
+ },
97
+ {
98
+ "symbol": "NXPI",
99
+ "trades": 4,
100
+ "pnl": 0.93,
101
+ "wins": 3,
102
+ "win_rate_pct": 75.0
103
+ },
104
+ {
105
+ "symbol": "MRNA",
106
+ "trades": 2,
107
+ "pnl": 0.83,
108
+ "wins": 1,
109
+ "win_rate_pct": 50.0
110
+ },
111
+ {
112
+ "symbol": "INTU",
113
+ "trades": 2,
114
+ "pnl": 0.66,
115
+ "wins": 1,
116
+ "win_rate_pct": 50.0
117
+ },
118
+ {
119
+ "symbol": "TXN",
120
+ "trades": 1,
121
+ "pnl": 0.61,
122
+ "wins": 1,
123
+ "win_rate_pct": 100.0
124
+ },
125
+ {
126
+ "symbol": "MAR",
127
+ "trades": 3,
128
+ "pnl": 0.55,
129
+ "wins": 2,
130
+ "win_rate_pct": 66.7
131
+ },
132
+ {
133
+ "symbol": "DASH",
134
+ "trades": 3,
135
+ "pnl": 0.51,
136
+ "wins": 1,
137
+ "win_rate_pct": 33.3
138
+ },
139
+ {
140
+ "symbol": "ABNB",
141
+ "trades": 2,
142
+ "pnl": 0.47,
143
+ "wins": 1,
144
+ "win_rate_pct": 50.0
145
+ },
146
+ {
147
+ "symbol": "FTNT",
148
+ "trades": 1,
149
+ "pnl": 0.43,
150
+ "wins": 1,
151
+ "win_rate_pct": 100.0
152
+ },
153
+ {
154
+ "symbol": "CTAS",
155
+ "trades": 1,
156
+ "pnl": 0.41,
157
+ "wins": 1,
158
+ "win_rate_pct": 100.0
159
+ },
160
+ {
161
+ "symbol": "SHOP",
162
+ "trades": 1,
163
+ "pnl": 0.37,
164
+ "wins": 1,
165
+ "win_rate_pct": 100.0
166
+ },
167
+ {
168
+ "symbol": "GILD",
169
+ "trades": 1,
170
+ "pnl": 0.31,
171
+ "wins": 1,
172
+ "win_rate_pct": 100.0
173
+ },
174
+ {
175
+ "symbol": "TRI",
176
+ "trades": 2,
177
+ "pnl": 0.25,
178
+ "wins": 1,
179
+ "win_rate_pct": 50.0
180
+ },
181
+ {
182
+ "symbol": "GEHC",
183
+ "trades": 2,
184
+ "pnl": 0.24,
185
+ "wins": 2,
186
+ "win_rate_pct": 100.0
187
+ },
188
+ {
189
+ "symbol": "CCEP",
190
+ "trades": 3,
191
+ "pnl": 0.19,
192
+ "wins": 2,
193
+ "win_rate_pct": 66.7
194
+ },
195
+ {
196
+ "symbol": "FAST",
197
+ "trades": 1,
198
+ "pnl": 0.18,
199
+ "wins": 1,
200
+ "win_rate_pct": 100.0
201
+ },
202
+ {
203
+ "symbol": "PEP",
204
+ "trades": 1,
205
+ "pnl": 0.17,
206
+ "wins": 1,
207
+ "win_rate_pct": 100.0
208
+ },
209
+ {
210
+ "symbol": "DXCM",
211
+ "trades": 2,
212
+ "pnl": 0.16,
213
+ "wins": 2,
214
+ "win_rate_pct": 100.0
215
+ },
216
+ {
217
+ "symbol": "DDOG",
218
+ "trades": 2,
219
+ "pnl": 0.14,
220
+ "wins": 1,
221
+ "win_rate_pct": 50.0
222
+ },
223
+ {
224
+ "symbol": "KDP",
225
+ "trades": 1,
226
+ "pnl": 0.12,
227
+ "wins": 1,
228
+ "win_rate_pct": 100.0
229
+ },
230
+ {
231
+ "symbol": "WMT",
232
+ "trades": 2,
233
+ "pnl": 0.11,
234
+ "wins": 1,
235
+ "win_rate_pct": 50.0
236
+ },
237
+ {
238
+ "symbol": "EXC",
239
+ "trades": 1,
240
+ "pnl": 0.07,
241
+ "wins": 1,
242
+ "win_rate_pct": 100.0
243
+ },
244
+ {
245
+ "symbol": "MNST",
246
+ "trades": 1,
247
+ "pnl": 0.07,
248
+ "wins": 1,
249
+ "win_rate_pct": 100.0
250
+ },
251
+ {
252
+ "symbol": "AEP",
253
+ "trades": 2,
254
+ "pnl": 0.07,
255
+ "wins": 1,
256
+ "win_rate_pct": 50.0
257
+ },
258
+ {
259
+ "symbol": "HON",
260
+ "trades": 1,
261
+ "pnl": 0.06,
262
+ "wins": 1,
263
+ "win_rate_pct": 100.0
264
+ },
265
+ {
266
+ "symbol": "PYPL",
267
+ "trades": 1,
268
+ "pnl": 0.04,
269
+ "wins": 1,
270
+ "win_rate_pct": 100.0
271
+ },
272
+ {
273
+ "symbol": "ADBE",
274
+ "trades": 4,
275
+ "pnl": 0.02,
276
+ "wins": 2,
277
+ "win_rate_pct": 50.0
278
+ },
279
+ {
280
+ "symbol": "ROST",
281
+ "trades": 2,
282
+ "pnl": -0.03,
283
+ "wins": 1,
284
+ "win_rate_pct": 50.0
285
+ },
286
+ {
287
+ "symbol": "CPRT",
288
+ "trades": 1,
289
+ "pnl": -0.09,
290
+ "wins": 0,
291
+ "win_rate_pct": 0.0
292
+ },
293
+ {
294
+ "symbol": "CMCSA",
295
+ "trades": 3,
296
+ "pnl": -0.1,
297
+ "wins": 1,
298
+ "win_rate_pct": 33.3
299
+ },
300
+ {
301
+ "symbol": "APP",
302
+ "trades": 1,
303
+ "pnl": -0.1,
304
+ "wins": 0,
305
+ "win_rate_pct": 0.0
306
+ },
307
+ {
308
+ "symbol": "PDD",
309
+ "trades": 2,
310
+ "pnl": -0.12,
311
+ "wins": 1,
312
+ "win_rate_pct": 50.0
313
+ },
314
+ {
315
+ "symbol": "XEL",
316
+ "trades": 1,
317
+ "pnl": -0.12,
318
+ "wins": 0,
319
+ "win_rate_pct": 0.0
320
+ },
321
+ {
322
+ "symbol": "ODFL",
323
+ "trades": 1,
324
+ "pnl": -0.14,
325
+ "wins": 0,
326
+ "win_rate_pct": 0.0
327
+ },
328
+ {
329
+ "symbol": "BKR",
330
+ "trades": 3,
331
+ "pnl": -0.27,
332
+ "wins": 0,
333
+ "win_rate_pct": 0.0
334
+ },
335
+ {
336
+ "symbol": "QCOM",
337
+ "trades": 2,
338
+ "pnl": -0.47,
339
+ "wins": 1,
340
+ "win_rate_pct": 50.0
341
+ },
342
+ {
343
+ "symbol": "BKNG",
344
+ "trades": 1,
345
+ "pnl": -0.58,
346
+ "wins": 0,
347
+ "win_rate_pct": 0.0
348
+ },
349
+ {
350
+ "symbol": "HONA",
351
+ "trades": 5,
352
+ "pnl": -0.6,
353
+ "wins": 3,
354
+ "win_rate_pct": 60.0
355
+ },
356
+ {
357
+ "symbol": "ROP",
358
+ "trades": 1,
359
+ "pnl": -0.65,
360
+ "wins": 0,
361
+ "win_rate_pct": 0.0
362
+ },
363
+ {
364
+ "symbol": "SPCX",
365
+ "trades": 1,
366
+ "pnl": -0.74,
367
+ "wins": 0,
368
+ "win_rate_pct": 0.0
369
+ },
370
+ {
371
+ "symbol": "ISRG",
372
+ "trades": 2,
373
+ "pnl": -1.51,
374
+ "wins": 0,
375
+ "win_rate_pct": 0.0
376
+ },
377
+ {
378
+ "symbol": "MRVL",
379
+ "trades": 1,
380
+ "pnl": -1.69,
381
+ "wins": 0,
382
+ "win_rate_pct": 0.0
383
+ },
384
+ {
385
+ "symbol": "AMGN",
386
+ "trades": 2,
387
+ "pnl": -1.73,
388
+ "wins": 0,
389
+ "win_rate_pct": 0.0
390
+ },
391
+ {
392
+ "symbol": "GOOGL",
393
+ "trades": 2,
394
+ "pnl": -2.53,
395
+ "wins": 0,
396
+ "win_rate_pct": 0.0
397
+ },
398
+ {
399
+ "symbol": "META",
400
+ "trades": 1,
401
+ "pnl": -3.53,
402
+ "wins": 0,
403
+ "win_rate_pct": 0.0
404
+ },
405
+ {
406
+ "symbol": "REGN",
407
+ "trades": 2,
408
+ "pnl": -5.47,
409
+ "wins": 0,
410
+ "win_rate_pct": 0.0
411
+ }
412
+ ],
413
+ "per_exit_reason": [
414
+ {
415
+ "exit_reason": "model_exit",
416
+ "trades": 42,
417
+ "pnl": 22.42,
418
+ "wins": 35,
419
+ "win_rate_pct": 83.3
420
+ },
421
+ {
422
+ "exit_reason": "take_profit",
423
+ "trades": 14,
424
+ "pnl": 8.63,
425
+ "wins": 14,
426
+ "win_rate_pct": 100.0
427
+ },
428
+ {
429
+ "exit_reason": "flatten_all",
430
+ "trades": 1,
431
+ "pnl": 2.1,
432
+ "wins": 1,
433
+ "win_rate_pct": 100.0
434
+ },
435
+ {
436
+ "exit_reason": "stop_loss",
437
+ "trades": 35,
438
+ "pnl": -32.89,
439
+ "wins": 1,
440
+ "win_rate_pct": 2.9
441
+ }
442
+ ]
443
+ }
stockpilot/data/reports/wf_stop12_walkforward_20261020_110650.json ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "aggregate": {
3
+ "label": "wf_stop12",
4
+ "folds": 3,
5
+ "compounded_return_pct": 0.621,
6
+ "mean_fold_return_pct": 0.207,
7
+ "positive_folds": 2,
8
+ "trades": 356,
9
+ "win_rate_pct": 61.52,
10
+ "profit_factor": 2.12,
11
+ "worst_drawdown_pct": -0.16,
12
+ "initial_cash": 10000.0
13
+ },
14
+ "folds": [
15
+ {
16
+ "fold": 1,
17
+ "start": "2026-09-16T13:30:00+00:00",
18
+ "end": "2026-09-25T19:55:00+00:00",
19
+ "metrics": {
20
+ "initial_cash": 10000.0,
21
+ "final_equity": 10037.4,
22
+ "total_return_pct": 0.374,
23
+ "max_drawdown_pct": -0.16,
24
+ "sharpe_daily_annualized": 9.223,
25
+ "trades": 150,
26
+ "win_rate_pct": 66.0,
27
+ "profit_factor": 3.104,
28
+ "avg_trade_pnl": 0.9209,
29
+ "avg_win": 2.0586,
30
+ "avg_loss": -1.2876,
31
+ "gross_profit": 203.8,
32
+ "gross_loss": 65.67,
33
+ "exposure_pct": 55.61,
34
+ "bars": 624,
35
+ "days": 8
36
+ },
37
+ "report_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/reports/wf_stop12_f1_20261020_105953.json",
38
+ "store_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/backtests/wf_stop12_f1_20261020_105937.db"
39
+ },
40
+ {
41
+ "fold": 2,
42
+ "start": "2026-09-28T13:30:00+00:00",
43
+ "end": "2026-10-07T19:55:00+00:00",
44
+ "metrics": {
45
+ "initial_cash": 10000.0,
46
+ "final_equity": 10026.21,
47
+ "total_return_pct": 0.262,
48
+ "max_drawdown_pct": -0.069,
49
+ "sharpe_daily_annualized": 9.962,
50
+ "trades": 114,
51
+ "win_rate_pct": 60.53,
52
+ "profit_factor": 1.613,
53
+ "avg_trade_pnl": 0.2908,
54
+ "avg_win": 1.2644,
55
+ "avg_loss": -1.202,
56
+ "gross_profit": 87.24,
57
+ "gross_loss": 54.09,
58
+ "exposure_pct": 42.15,
59
+ "bars": 624,
60
+ "days": 8
61
+ },
62
+ "report_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/reports/wf_stop12_f2_20261020_110322.json",
63
+ "store_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/backtests/wf_stop12_f2_20261020_110259.db"
64
+ },
65
+ {
66
+ "fold": 3,
67
+ "start": "2026-10-08T13:30:00+00:00",
68
+ "end": "2026-10-19T20:00:00+00:00",
69
+ "metrics": {
70
+ "initial_cash": 10000.0,
71
+ "final_equity": 9998.36,
72
+ "total_return_pct": -0.016,
73
+ "max_drawdown_pct": -0.104,
74
+ "sharpe_daily_annualized": -3.035,
75
+ "trades": 92,
76
+ "win_rate_pct": 55.43,
77
+ "profit_factor": 1.008,
78
+ "avg_trade_pnl": 0.0029,
79
+ "avg_win": 0.6607,
80
+ "avg_loss": -0.8155,
81
+ "gross_profit": 33.7,
82
+ "gross_loss": 33.43,
83
+ "exposure_pct": 47.84,
84
+ "bars": 625,
85
+ "days": 8
86
+ },
87
+ "report_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/reports/wf_stop12_f3_20261020_110650.json",
88
+ "store_path": "/Users/jeffreytse/Documents/New OpenCode Project/stockpilot/data/backtests/wf_stop12_f3_20261020_110630.db"
89
+ }
90
+ ]
91
+ }
stockpilot/src/stockpilot/brokers/webull.py CHANGED
@@ -9,6 +9,7 @@ create user-visible confusion, so a failure is surfaced instead.
9
  from __future__ import annotations
10
 
11
  import logging
 
12
  from typing import Any
13
 
14
  from ..config import Settings
@@ -27,10 +28,7 @@ from .base import Broker, BrokerAuthError, BrokerRejected, BrokerUnavailable
27
 
28
  LOGGER = logging.getLogger(__name__)
29
 
30
- _ENDPOINTS = {
31
- "production": "api.webull.hk",
32
- "sandbox": "api.sandbox.webull.hk",
33
- }
34
  _STATUS_MAP = {
35
  "PENDING": OrderStatus.PENDING,
36
  "SUBMITTED": OrderStatus.SUBMITTED,
@@ -81,7 +79,10 @@ class WebullBroker(Broker):
81
  self.settings.webull_app_secret,
82
  region,
83
  )
84
- self._api_client.add_endpoint(region, _ENDPOINTS[self.settings.webull_env])
 
 
 
85
  self._trade_client = TradeClient(self._api_client)
86
  if not self.account_id:
87
  payload = self._json(self._trade_client.account_v2.get_account_list())
 
9
  from __future__ import annotations
10
 
11
  import logging
12
+ import sys
13
  from typing import Any
14
 
15
  from ..config import Settings
 
28
 
29
  LOGGER = logging.getLogger(__name__)
30
 
31
+ _SANDBOX_ENDPOINT = "api.sandbox.webull.com"
 
 
 
32
  _STATUS_MAP = {
33
  "PENDING": OrderStatus.PENDING,
34
  "SUBMITTED": OrderStatus.SUBMITTED,
 
79
  self.settings.webull_app_secret,
80
  region,
81
  )
82
+ if self.settings.webull_env == "sandbox":
83
+ self._api_client.add_endpoint(region, _SANDBOX_ENDPOINT)
84
+ # Prevent the SDK from creating webull_trade_sdk.log in the CWD.
85
+ self._api_client.set_stream_logger(log_level=logging.WARNING, stream=sys.stderr)
86
  self._trade_client = TradeClient(self._api_client)
87
  if not self.account_id:
88
  payload = self._json(self._trade_client.account_v2.get_account_list())
stockpilot/src/stockpilot/doctor.py CHANGED
@@ -2,11 +2,12 @@
2
 
3
  from __future__ import annotations
4
 
5
- from datetime import UTC, datetime, timedelta
6
  from typing import Any
7
 
8
  from .config import Settings
9
  from .domain import utcnow
 
10
  from .market.universe import Universe
11
  from .store import Store
12
  from .strategy.model import TurningPointModel
@@ -49,11 +50,13 @@ def run_doctor(settings: Settings, store: Store) -> dict[str, Any]:
49
  if symbols_with_bars == 0:
50
  add("bars", "fail", "no cached bars")
51
  else:
52
- stale = latest is None or utcnow() - latest > timedelta(days=4)
 
53
  add(
54
  "bars",
55
  "warn" if stale else "pass",
56
- f"{total_bars} recent bars across {symbols_with_bars} symbols; latest={latest}",
 
57
  )
58
 
59
  if settings.model_path and settings.model_path.exists():
 
2
 
3
  from __future__ import annotations
4
 
5
+ from datetime import UTC, datetime
6
  from typing import Any
7
 
8
  from .config import Settings
9
  from .domain import utcnow
10
+ from .market.calendar import last_completed_session
11
  from .market.universe import Universe
12
  from .store import Store
13
  from .strategy.model import TurningPointModel
 
50
  if symbols_with_bars == 0:
51
  add("bars", "fail", "no cached bars")
52
  else:
53
+ expected = last_completed_session(utcnow())
54
+ stale = latest is None or latest.date() < expected
55
  add(
56
  "bars",
57
  "warn" if stale else "pass",
58
+ f"{total_bars} bars across {symbols_with_bars} symbols; latest={latest} "
59
+ f"expected session={expected}",
60
  )
61
 
62
  if settings.model_path and settings.model_path.exists():
stockpilot/src/stockpilot/engine/analytics.py CHANGED
@@ -21,9 +21,17 @@ def pair_trades(fills: list[dict[str, Any]]) -> list[dict[str, Any]]:
21
  price = float(fill["price"])
22
  fees = float(fill["fees"])
23
  ts = str(fill["ts"])
 
24
  if str(fill["side"]).upper() == "BUY":
25
  held = open_positions.setdefault(
26
- symbol, {"qty": 0.0, "avg": 0.0, "entry_ts": ts, "entry_fees": 0.0}
 
 
 
 
 
 
 
27
  )
28
  total = held["qty"] + qty
29
  held["avg"] = (held["avg"] * held["qty"] + price * qty) / total
@@ -47,6 +55,8 @@ def pair_trades(fills: list[dict[str, Any]]) -> list[dict[str, Any]]:
47
  "return_pct": round((price / position["avg"] - 1) * 100, 4)
48
  if position["avg"]
49
  else 0.0,
 
 
50
  }
51
  )
52
  position["qty"] -= qty
@@ -99,6 +109,7 @@ def performance(
99
  "gross_loss": round(gross_loss, 2),
100
  "days": int(daily.shape[0]),
101
  "per_symbol": per_symbol(trades),
 
102
  }
103
 
104
 
@@ -123,6 +134,29 @@ def per_symbol(trades: list[dict[str, Any]]) -> list[dict[str, Any]]:
123
  ]
124
 
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  def build_report(store: Store, initial_cash: float, days: int = 0) -> dict[str, Any]:
127
  fills = store.recent_fills(limit=10_000_000)
128
  equity = store.equity_series(limit=1_000_000)
 
21
  price = float(fill["price"])
22
  fees = float(fill["fees"])
23
  ts = str(fill["ts"])
24
+ reason = str(fill.get("reason", ""))
25
  if str(fill["side"]).upper() == "BUY":
26
  held = open_positions.setdefault(
27
+ symbol,
28
+ {
29
+ "qty": 0.0,
30
+ "avg": 0.0,
31
+ "entry_ts": ts,
32
+ "entry_fees": 0.0,
33
+ "entry_reason": reason,
34
+ },
35
  )
36
  total = held["qty"] + qty
37
  held["avg"] = (held["avg"] * held["qty"] + price * qty) / total
 
55
  "return_pct": round((price / position["avg"] - 1) * 100, 4)
56
  if position["avg"]
57
  else 0.0,
58
+ "entry_reason": position["entry_reason"],
59
+ "exit_reason": reason,
60
  }
61
  )
62
  position["qty"] -= qty
 
109
  "gross_loss": round(gross_loss, 2),
110
  "days": int(daily.shape[0]),
111
  "per_symbol": per_symbol(trades),
112
+ "per_exit_reason": group_trades(trades, "exit_reason"),
113
  }
114
 
115
 
 
134
  ]
135
 
136
 
137
+ def group_trades(trades: list[dict[str, Any]], key: str) -> list[dict[str, Any]]:
138
+ if not trades:
139
+ return []
140
+ frame = pd.DataFrame(trades)
141
+ if key not in frame.columns:
142
+ return []
143
+ grouped = (
144
+ frame.groupby(key)
145
+ .agg(
146
+ trades=("pnl", "size"),
147
+ pnl=("pnl", "sum"),
148
+ wins=("pnl", lambda values: (values > 0).sum()),
149
+ )
150
+ .reset_index()
151
+ )
152
+ grouped["pnl"] = grouped["pnl"].round(2)
153
+ grouped["win_rate_pct"] = (100 * grouped["wins"] / grouped["trades"]).round(1)
154
+ return [
155
+ {str(k): v for k, v in record.items()}
156
+ for record in grouped.sort_values("pnl", ascending=False).to_dict("records")
157
+ ]
158
+
159
+
160
  def build_report(store: Store, initial_cash: float, days: int = 0) -> dict[str, Any]:
161
  fills = store.recent_fills(limit=10_000_000)
162
  equity = store.equity_series(limit=1_000_000)
stockpilot/src/stockpilot/engine/backtest.py CHANGED
@@ -22,7 +22,7 @@ from ..store import Store
22
  from ..strategy.engine import SignalEngine
23
  from ..strategy.features import compute_features
24
  from ..strategy.model import TurningPointModel
25
- from .analytics import pair_trades
26
 
27
  LOGGER = logging.getLogger(__name__)
28
 
@@ -187,6 +187,7 @@ class Backtester:
187
  },
188
  "metrics": metrics,
189
  "per_symbol": _per_symbol(trades),
 
190
  }
191
  report_path = None
192
  if self.config.write_report:
 
22
  from ..strategy.engine import SignalEngine
23
  from ..strategy.features import compute_features
24
  from ..strategy.model import TurningPointModel
25
+ from .analytics import group_trades, pair_trades
26
 
27
  LOGGER = logging.getLogger(__name__)
28
 
 
187
  },
188
  "metrics": metrics,
189
  "per_symbol": _per_symbol(trades),
190
+ "per_exit_reason": group_trades(trades, "exit_reason"),
191
  }
192
  report_path = None
193
  if self.config.write_report:
stockpilot/src/stockpilot/engine/runner.py CHANGED
@@ -97,6 +97,8 @@ class PaperRunner:
97
  self._features: dict[str, tuple[pd.Timestamp, pd.DataFrame]] = {}
98
  self._probs: dict[str, tuple[pd.Timestamp, tuple[float, float]]] = {}
99
  self._snapshots: dict[str, Quote] = {}
 
 
100
  self._interval_seconds = {"1m": 60, "5m": 300, "15m": 900, "1h": 3600}.get(
101
  settings.bar_interval, 300
102
  )
@@ -184,6 +186,12 @@ class PaperRunner:
184
 
185
  # ---------------------------------------------------------------- bars
186
  def _load_bars(self, now: datetime) -> dict[str, pd.DataFrame]:
 
 
 
 
 
 
187
  try:
188
  frames = self.provider.get_bars_batch(
189
  self.universe.symbols(), self.settings.bar_interval, limit=340
@@ -202,6 +210,9 @@ class PaperRunner:
202
  frame = frame.iloc[:-1]
203
  if len(frame) >= 220:
204
  out[symbol] = frame
 
 
 
205
  return out
206
 
207
  def _probabilities_for(self, symbol: str, feats: pd.DataFrame) -> tuple[float, float]:
 
97
  self._features: dict[str, tuple[pd.Timestamp, pd.DataFrame]] = {}
98
  self._probs: dict[str, tuple[pd.Timestamp, tuple[float, float]]] = {}
99
  self._snapshots: dict[str, Quote] = {}
100
+ self._bars_cache: dict[str, pd.DataFrame] = {}
101
+ self._bars_cached_at: datetime | None = None
102
  self._interval_seconds = {"1m": 60, "5m": 300, "15m": 900, "1h": 3600}.get(
103
  settings.bar_interval, 300
104
  )
 
186
 
187
  # ---------------------------------------------------------------- bars
188
  def _load_bars(self, now: datetime) -> dict[str, pd.DataFrame]:
189
+ if (
190
+ self._bars_cache
191
+ and self._bars_cached_at is not None
192
+ and (now - self._bars_cached_at).total_seconds() < self._interval_seconds
193
+ ):
194
+ return self._bars_cache
195
  try:
196
  frames = self.provider.get_bars_batch(
197
  self.universe.symbols(), self.settings.bar_interval, limit=340
 
210
  frame = frame.iloc[:-1]
211
  if len(frame) >= 220:
212
  out[symbol] = frame
213
+ if out:
214
+ self._bars_cache = out
215
+ self._bars_cached_at = now
216
  return out
217
 
218
  def _probabilities_for(self, symbol: str, feats: pd.DataFrame) -> tuple[float, float]:
stockpilot/src/stockpilot/market/calendar.py CHANGED
@@ -77,6 +77,13 @@ def session_label(ts: datetime) -> str:
77
  return to_et(ts).date().isoformat()
78
 
79
 
 
 
 
 
 
 
 
80
  def previous_session(day: date | datetime) -> date:
81
  target = _as_date(day)
82
  session = _CAL.date_to_session(pd.Timestamp(target), direction="previous")
 
77
  return to_et(ts).date().isoformat()
78
 
79
 
80
+ def last_completed_session(ts: datetime) -> date:
81
+ et = to_et(ts)
82
+ if is_session_day(et) and et.time() >= RTH_CLOSE:
83
+ return et.date()
84
+ return previous_session(et)
85
+
86
+
87
  def previous_session(day: date | datetime) -> date:
88
  target = _as_date(day)
89
  session = _CAL.date_to_session(pd.Timestamp(target), direction="previous")
stockpilot/src/stockpilot/store.py CHANGED
@@ -338,7 +338,10 @@ class Store:
338
  def recent_fills(self, limit: int = 200) -> list[dict[str, Any]]:
339
  with self._lock:
340
  rows = self.db.execute(
341
- "SELECT * FROM fills ORDER BY id DESC LIMIT ?", (limit,)
 
 
 
342
  ).fetchall()
343
  return [dict(r) for r in rows]
344
 
 
338
  def recent_fills(self, limit: int = 200) -> list[dict[str, Any]]:
339
  with self._lock:
340
  rows = self.db.execute(
341
+ "SELECT f.*, COALESCE(o.reason, '') AS reason FROM fills f"
342
+ " LEFT JOIN orders o ON o.client_order_id = f.client_order_id"
343
+ " ORDER BY f.id DESC LIMIT ?",
344
+ (limit,),
345
  ).fetchall()
346
  return [dict(r) for r in rows]
347
 
stockpilot/tests/test_analytics.py CHANGED
@@ -1,7 +1,7 @@
1
  from stockpilot.engine.analytics import pair_trades, performance
2
 
3
 
4
- def fill(ts, side, qty, price, fees=0.0):
5
  return {
6
  "ts": ts,
7
  "symbol": "AAPL",
@@ -9,21 +9,27 @@ def fill(ts, side, qty, price, fees=0.0):
9
  "qty": qty,
10
  "price": price,
11
  "fees": fees,
 
12
  }
13
 
14
 
15
  def test_pair_trades_handles_partial_exits():
16
  trades = pair_trades(
17
  [
18
- fill("2026-10-20T13:30:00+00:00", "BUY", 2, 100),
19
- fill("2026-10-20T13:35:00+00:00", "SELL", 1, 101, 0.01),
20
- fill("2026-10-20T13:40:00+00:00", "SELL", 1, 99, 0.01),
21
  ]
22
  )
23
  assert len(trades) == 2
24
  assert trades[0]["qty"] == 1
25
  assert trades[0]["pnl"] == 0.99
26
  assert trades[1]["pnl"] == -1.01
 
 
 
 
 
27
 
28
 
29
  def test_performance_metrics():
 
1
  from stockpilot.engine.analytics import pair_trades, performance
2
 
3
 
4
+ def fill(ts, side, qty, price, fees=0.0, reason=""):
5
  return {
6
  "ts": ts,
7
  "symbol": "AAPL",
 
9
  "qty": qty,
10
  "price": price,
11
  "fees": fees,
12
+ "reason": reason,
13
  }
14
 
15
 
16
  def test_pair_trades_handles_partial_exits():
17
  trades = pair_trades(
18
  [
19
+ fill("2026-10-20T13:30:00+00:00", "BUY", 2, 100, reason="model_entry"),
20
+ fill("2026-10-20T13:35:00+00:00", "SELL", 1, 101, 0.01, "model_exit"),
21
+ fill("2026-10-20T13:40:00+00:00", "SELL", 1, 99, 0.01, "stop_loss"),
22
  ]
23
  )
24
  assert len(trades) == 2
25
  assert trades[0]["qty"] == 1
26
  assert trades[0]["pnl"] == 0.99
27
  assert trades[1]["pnl"] == -1.01
28
+ assert trades[0]["entry_reason"] == "model_entry"
29
+ assert {trades[0]["exit_reason"], trades[1]["exit_reason"]} == {
30
+ "model_exit",
31
+ "stop_loss",
32
+ }
33
 
34
 
35
  def test_performance_metrics():
stockpilot/tests/test_calendar.py CHANGED
@@ -11,3 +11,14 @@ def test_next_open_skips_weekend():
11
  def test_next_open_after_close_rolls_to_next_day():
12
  target = next_open(datetime(2026, 10, 19, 21, 0, tzinfo=UTC))
13
  assert target == datetime(2026, 10, 20, 13, 30, tzinfo=UTC)
 
 
 
 
 
 
 
 
 
 
 
 
11
  def test_next_open_after_close_rolls_to_next_day():
12
  target = next_open(datetime(2026, 10, 19, 21, 0, tzinfo=UTC))
13
  assert target == datetime(2026, 10, 20, 13, 30, tzinfo=UTC)
14
+
15
+
16
+ def test_last_completed_session_uses_previous_day_before_close():
17
+ from stockpilot.market.calendar import last_completed_session
18
+
19
+ assert last_completed_session(datetime(2026, 10, 20, 12, 0, tzinfo=UTC)) == datetime(
20
+ 2026, 10, 19
21
+ ).date()
22
+ assert last_completed_session(datetime(2026, 10, 20, 21, 0, tzinfo=UTC)) == datetime(
23
+ 2026, 10, 20
24
+ ).date()
stockpilot/tests/test_runner.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from datetime import UTC, datetime, timedelta
4
+
5
+ import pandas as pd
6
+
7
+ from stockpilot.config import Settings
8
+ from stockpilot.domain import Quote
9
+ from stockpilot.engine.runner import PaperRunner
10
+ from stockpilot.market.base import MarketDataProvider
11
+ from stockpilot.market.universe import Instrument, Universe
12
+ from stockpilot.store import Store
13
+
14
+
15
+ class FakeProvider(MarketDataProvider):
16
+ name = "fake"
17
+
18
+ def __init__(self):
19
+ self.calls = 0
20
+
21
+ def get_bars(self, symbol, interval="5m", start=None, end=None, limit=None):
22
+ raise NotImplementedError
23
+
24
+ def get_bars_batch(self, symbols, interval="5m", start=None, end=None, limit=None):
25
+ self.calls += 1
26
+ index = pd.date_range(
27
+ end="2026-10-19 20:00", periods=340, freq="5min", tz="UTC"
28
+ )
29
+ frame = pd.DataFrame(
30
+ {
31
+ "open": 100.0,
32
+ "high": 101.0,
33
+ "low": 99.0,
34
+ "close": 100.5,
35
+ "volume": 1000.0,
36
+ },
37
+ index=index,
38
+ )
39
+ return {symbol: frame.copy() for symbol in symbols}
40
+
41
+ def get_snapshots(self, symbols):
42
+ return {
43
+ symbol: Quote(
44
+ symbol=symbol,
45
+ bid=100.0,
46
+ ask=100.1,
47
+ last=100.0,
48
+ ts=datetime(2026, 10, 19, 20, 0, tzinfo=UTC),
49
+ volume=1.0,
50
+ source="fake",
51
+ )
52
+ for symbol in symbols
53
+ }
54
+
55
+
56
+ def test_runner_reuses_bars_within_interval(settings: Settings, store: Store):
57
+ provider = FakeProvider()
58
+ runner = PaperRunner(
59
+ settings,
60
+ store,
61
+ Universe([Instrument(symbol="AAPL"), Instrument(symbol="MSFT")]),
62
+ provider,
63
+ )
64
+ start = datetime(2026, 10, 20, 14, 0, tzinfo=UTC)
65
+ first = runner._load_bars(start)
66
+ second = runner._load_bars(start + timedelta(seconds=30))
67
+ assert set(first) == {"AAPL", "MSFT"}
68
+ assert provider.calls == 1
69
+ assert second is first
70
+ runner._load_bars(start + timedelta(seconds=301))
71
+ assert provider.calls == 2