feat: judge.review compares each paper trade with the simulator
For a paper day, every order is lined up with what the validated simulator does on
the same recorded ticks: the sim exit from the real fill (stop, 6% trail after +1R,
20-min time stop, sell at the bid 300 ms after the trigger) vs the paper exit,
plus the sim R of orders that did not fill. Trades are flagged when R differs by
more than 0.3R, the exit reason differs, or the entry slipped. The report goes to
data/judge/reviews/<date>.md.
On 2026-09-30: paper -8.25R vs sim -3.97R on the same six fills. The gap is two
trades where Alpaca's paper engine filled a triggered stop 6-60 s late (CMCT,
PWCM; PWCM's own exit was also blocked by the stop-id bug fixed in f3c8be1).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B3PXXn2tHBzdv6rYtGPz86
This commit is contained in:
1 parent
358b859c59
commit
5315e99978
2 files changed
+191
No files matched your search
@@ -0,0 +1,31 @@
|
||||
"""judge.review.sim_exit reproduces the simulator's exit rules on synthetic ticks."""
|
||||
import pandas as pd
|
||||
|
||||
from judge.review import sim_exit
|
||||
|
||||
T0 = pd.Timestamp("2026-09-30 10:00:00")
|
||||
|
||||
|
||||
def tape(prices, step_s=1):
|
||||
t = [T0 + pd.Timedelta(seconds=step_s * (i + 1)) for i in range(len(prices))]
|
||||
T = pd.DataFrame({"t": t, "p": prices, "s": 100})
|
||||
Q = pd.DataFrame({"t": t, "bp": [p - 0.01 for p in prices], "bs": 100, "ap": [p + 0.01 for p in prices], "as": 100})
|
||||
return T, Q
|
||||
|
||||
|
||||
def test_stop_sells_at_the_bid_after_the_breach():
|
||||
T, Q = tape([10.0, 9.9, 9.5, 9.4])
|
||||
s = sim_exit(T, Q, T0, 10.0, 9.5)
|
||||
assert s["reason"] == "stop" and round(s["exit"], 2) == 9.49 and round(s["r"], 2) == -1.02
|
||||
|
||||
|
||||
def test_trail_after_one_r_gives_back_six_percent():
|
||||
T, Q = tape([10.5, 11.0, 12.0, 11.2, 11.0]) # risk 0.5: +1R at 10.5; trail 6% under 12.0 = 11.28
|
||||
s = sim_exit(T, Q, T0, 10.0, 9.5)
|
||||
assert s["reason"] == "trail" and round(s["exit"], 2) == 11.19
|
||||
|
||||
|
||||
def test_time_stop_after_twenty_minutes():
|
||||
T, Q = tape([10.1] * 30, step_s=60)
|
||||
s = sim_exit(T, Q, T0, 10.0, 9.5)
|
||||
assert s["reason"] == "time"
|
||||
Reference in new issue
Block a user