style: Clean up code formatting for improved readability
CI / lint-test-build (push) Failing after 14s
CI / lint-test-build (push) Failing after 14s
This commit is contained in:
@@ -30,8 +30,7 @@ def _parse_balances(raw: str) -> Mapping[str, float]:
|
|||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(description="Run a deterministic replay backtest.")
|
||||||
description="Run a deterministic replay backtest.")
|
|
||||||
parser.add_argument("--events", type=Path, required=True)
|
parser.add_argument("--events", type=Path, required=True)
|
||||||
parser.add_argument("--starting-balances", type=str, default="USD=1000.0")
|
parser.add_argument("--starting-balances", type=str, default="USD=1000.0")
|
||||||
parser.add_argument("--trade-capital", type=float, default=100.0)
|
parser.add_argument("--trade-capital", type=float, default=100.0)
|
||||||
@@ -56,18 +55,15 @@ def main() -> int:
|
|||||||
started_at=events[0].occurred_at if events else datetime.now(UTC),
|
started_at=events[0].occurred_at if events else datetime.now(UTC),
|
||||||
)
|
)
|
||||||
report = asyncio.run(
|
report = asyncio.run(
|
||||||
engine.run(events, starting_balances=_parse_balances(
|
engine.run(events, starting_balances=_parse_balances(args.starting_balances))
|
||||||
args.starting_balances))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
print("Backtest report:")
|
print("Backtest report:")
|
||||||
print(f"- processed_events: {report.processed_events}")
|
print(f"- processed_events: {report.processed_events}")
|
||||||
print(f"- opportunities_seen: {report.opportunities_seen}")
|
print(f"- opportunities_seen: {report.opportunities_seen}")
|
||||||
print(f"- trades_executed: {report.trades_executed}")
|
print(f"- trades_executed: {report.trades_executed}")
|
||||||
print(
|
print(f"- win_rate: {report.win_rate if report.win_rate is not None else 'n/a'}")
|
||||||
f"- win_rate: {report.win_rate if report.win_rate is not None else 'n/a'}")
|
print(f"- fill_rate: {report.fill_rate if report.fill_rate is not None else 'n/a'}")
|
||||||
print(
|
|
||||||
f"- fill_rate: {report.fill_rate if report.fill_rate is not None else 'n/a'}")
|
|
||||||
print(f"- realized_pnl_usd: {report.realized_pnl_usd:.4f}")
|
print(f"- realized_pnl_usd: {report.realized_pnl_usd:.4f}")
|
||||||
print(f"- max_drawdown_usd: {report.max_drawdown_usd:.4f}")
|
print(f"- max_drawdown_usd: {report.max_drawdown_usd:.4f}")
|
||||||
print(f"- miss_reasons: {dict(report.miss_reasons)}")
|
print(f"- miss_reasons: {dict(report.miss_reasons)}")
|
||||||
|
|||||||
@@ -63,16 +63,13 @@ def scan_worktree() -> list[str]:
|
|||||||
|
|
||||||
for rule_name, pattern in PATTERNS:
|
for rule_name, pattern in PATTERNS:
|
||||||
if pattern.search(content):
|
if pattern.search(content):
|
||||||
findings.append(
|
findings.append(f"worktree:{path.relative_to(WORKSPACE)}:{rule_name}")
|
||||||
f"worktree:{path.relative_to(WORKSPACE)}:{rule_name}")
|
|
||||||
return findings
|
return findings
|
||||||
|
|
||||||
|
|
||||||
def scan_git_history() -> list[str]:
|
def scan_git_history() -> list[str]:
|
||||||
cmd = ["git", "-C", str(WORKSPACE), "log", "--all",
|
cmd = ["git", "-C", str(WORKSPACE), "log", "--all", "-p", "--pretty=format:%H"]
|
||||||
"-p", "--pretty=format:%H"]
|
completed = subprocess.run(cmd, check=False, capture_output=True, text=True)
|
||||||
completed = subprocess.run(
|
|
||||||
cmd, check=False, capture_output=True, text=True)
|
|
||||||
if completed.returncode != 0:
|
if completed.returncode != 0:
|
||||||
return ["history_scan_failed"]
|
return ["history_scan_failed"]
|
||||||
|
|
||||||
|
|||||||
@@ -153,8 +153,7 @@ def _parse_book_levels(raw_levels: Any) -> tuple[BookLevel, ...]:
|
|||||||
or not isinstance(raw_level[1], int | float)
|
or not isinstance(raw_level[1], int | float)
|
||||||
):
|
):
|
||||||
raise ValueError("Each level must be [price, volume]")
|
raise ValueError("Each level must be [price, volume]")
|
||||||
levels.append(BookLevel(price=float(
|
levels.append(BookLevel(price=float(raw_level[0]), volume=float(raw_level[1])))
|
||||||
raw_level[0]), volume=float(raw_level[1])))
|
|
||||||
|
|
||||||
return tuple(levels)
|
return tuple(levels)
|
||||||
|
|
||||||
@@ -173,8 +172,7 @@ def load_replay_events(path: Path) -> list[ReplayBookEvent]:
|
|||||||
if not isinstance(timestamp_raw, str) or not isinstance(symbol_raw, str):
|
if not isinstance(timestamp_raw, str) or not isinstance(symbol_raw, str):
|
||||||
raise ValueError("Each event must include timestamp and symbol")
|
raise ValueError("Each event must include timestamp and symbol")
|
||||||
|
|
||||||
occurred_at = datetime.fromisoformat(
|
occurred_at = datetime.fromisoformat(timestamp_raw.replace("Z", "+00:00")).astimezone(UTC)
|
||||||
timestamp_raw.replace("Z", "+00:00")).astimezone(UTC)
|
|
||||||
events.append(
|
events.append(
|
||||||
ReplayBookEvent(
|
ReplayBookEvent(
|
||||||
occurred_at=occurred_at,
|
occurred_at=occurred_at,
|
||||||
@@ -208,8 +206,7 @@ class BacktestReplayEngine:
|
|||||||
min_order_size_by_pair=config.min_order_size_by_pair,
|
min_order_size_by_pair=config.min_order_size_by_pair,
|
||||||
)
|
)
|
||||||
self._pre_trade = PreTradeValidator()
|
self._pre_trade = PreTradeValidator()
|
||||||
self._trade_limits = TradeLimitsGuard(
|
self._trade_limits = TradeLimitsGuard(max_concurrent_trades=config.max_concurrent_trades)
|
||||||
max_concurrent_trades=config.max_concurrent_trades)
|
|
||||||
self._simulated_rest = _SimulatedRestClient(
|
self._simulated_rest = _SimulatedRestClient(
|
||||||
self._clock,
|
self._clock,
|
||||||
slippage_bps=config.slippage_bps,
|
slippage_bps=config.slippage_bps,
|
||||||
@@ -244,8 +241,7 @@ class BacktestReplayEngine:
|
|||||||
trades_executed = 0
|
trades_executed = 0
|
||||||
|
|
||||||
realized_pnl = 0.0
|
realized_pnl = 0.0
|
||||||
equity = float(starting_balances.get(
|
equity = float(starting_balances.get(self._config.quote_asset.upper(), 0.0))
|
||||||
self._config.quote_asset.upper(), 0.0))
|
|
||||||
peak_equity = equity
|
peak_equity = equity
|
||||||
max_drawdown = 0.0
|
max_drawdown = 0.0
|
||||||
|
|
||||||
@@ -288,8 +284,7 @@ class BacktestReplayEngine:
|
|||||||
result = await self._sequencer.execute(opportunity)
|
result = await self._sequencer.execute(opportunity)
|
||||||
self._trade_limits.close_trade(exposure)
|
self._trade_limits.close_trade(exposure)
|
||||||
|
|
||||||
execution_latencies.append(
|
execution_latencies.append(self._simulated_rest.last_trade_latency_ms)
|
||||||
self._simulated_rest.last_trade_latency_ms)
|
|
||||||
fill_samples.append(self._simulated_rest.last_fill_ratio)
|
fill_samples.append(self._simulated_rest.last_fill_ratio)
|
||||||
|
|
||||||
if not result.success:
|
if not result.success:
|
||||||
@@ -312,8 +307,7 @@ class BacktestReplayEngine:
|
|||||||
|
|
||||||
wins = sum(1 for pnl in realized_samples if pnl > 0.0)
|
wins = sum(1 for pnl in realized_samples if pnl > 0.0)
|
||||||
win_rate = (wins / len(realized_samples)) if realized_samples else None
|
win_rate = (wins / len(realized_samples)) if realized_samples else None
|
||||||
fill_rate = (sum(fill_samples) / len(fill_samples)
|
fill_rate = (sum(fill_samples) / len(fill_samples)) if fill_samples else None
|
||||||
) if fill_samples else None
|
|
||||||
|
|
||||||
return BacktestReport(
|
return BacktestReport(
|
||||||
started_at=events[0].occurred_at if events else self._clock.now,
|
started_at=events[0].occurred_at if events else self._clock.now,
|
||||||
|
|||||||
@@ -140,8 +140,7 @@ async def restore_runtime_state(app: FastAPI) -> RuntimeRecoveryReport:
|
|||||||
snapshot_at = latest.snapshot_at.isoformat()
|
snapshot_at = latest.snapshot_at.isoformat()
|
||||||
controls.is_running = latest.is_running
|
controls.is_running = latest.is_running
|
||||||
if latest.kill_switch_active:
|
if latest.kill_switch_active:
|
||||||
controls.kill_switch.activate(
|
controls.kill_switch.activate(reason=latest.kill_switch_reason or "recovered")
|
||||||
reason=latest.kill_switch_reason or "recovered")
|
|
||||||
else:
|
else:
|
||||||
controls.kill_switch.deactivate()
|
controls.kill_switch.deactivate()
|
||||||
controls.mark_updated()
|
controls.mark_updated()
|
||||||
@@ -151,8 +150,7 @@ async def restore_runtime_state(app: FastAPI) -> RuntimeRecoveryReport:
|
|||||||
if open_trades > 0:
|
if open_trades > 0:
|
||||||
controls.is_running = False
|
controls.is_running = False
|
||||||
if not controls.kill_switch.is_active:
|
if not controls.kill_switch.is_active:
|
||||||
controls.kill_switch.activate(
|
controls.kill_switch.activate(reason="recovery_open_trades_detected")
|
||||||
reason="recovery_open_trades_detected")
|
|
||||||
controls.mark_updated()
|
controls.mark_updated()
|
||||||
restart_guard_active = True
|
restart_guard_active = True
|
||||||
|
|
||||||
|
|||||||
+6
-12
@@ -191,8 +191,7 @@ async def test_dashboard_page_and_fragment_and_sse(tmp_path) -> None:
|
|||||||
assert "trade-open" in overview.text
|
assert "trade-open" in overview.text
|
||||||
|
|
||||||
assert overview_stream.status_code == 200
|
assert overview_stream.status_code == 200
|
||||||
assert overview_stream.headers["content-type"].startswith(
|
assert overview_stream.headers["content-type"].startswith("text/event-stream")
|
||||||
"text/event-stream")
|
|
||||||
assert "event: overview" in overview_stream.text
|
assert "event: overview" in overview_stream.text
|
||||||
assert "trade-open" in overview_stream.text
|
assert "trade-open" in overview_stream.text
|
||||||
|
|
||||||
@@ -262,8 +261,7 @@ async def test_dashboard_controls_update_runtime_state_and_config(tmp_path) -> N
|
|||||||
assert app.state.settings.max_trade_capital_usd == 300.0
|
assert app.state.settings.max_trade_capital_usd == 300.0
|
||||||
assert app.state.settings.max_concurrent_trades == 4
|
assert app.state.settings.max_concurrent_trades == 4
|
||||||
assert app.state.settings.paper_trading_mode is True
|
assert app.state.settings.paper_trading_mode is True
|
||||||
assert app.state.dashboard_controls.tradable_pairs == [
|
assert app.state.dashboard_controls.tradable_pairs == ["BTC/USD", "ETH/BTC"]
|
||||||
"BTC/USD", "ETH/BTC"]
|
|
||||||
assert app.state.dashboard_controls.strategy_mode == "paper"
|
assert app.state.dashboard_controls.strategy_mode == "paper"
|
||||||
assert app.state.dashboard_controls.strategy_profit_threshold == 0.0025
|
assert app.state.dashboard_controls.strategy_profit_threshold == 0.0025
|
||||||
assert app.state.dashboard_controls.strategy_max_depth_levels == 7
|
assert app.state.dashboard_controls.strategy_max_depth_levels == 7
|
||||||
@@ -275,14 +273,10 @@ async def test_dashboard_controls_update_runtime_state_and_config(tmp_path) -> N
|
|||||||
assert audit_recent.status_code == 200
|
assert audit_recent.status_code == 200
|
||||||
entries = audit_recent.json()["entries"]
|
entries = audit_recent.json()["entries"]
|
||||||
assert len(entries) >= 4
|
assert len(entries) >= 4
|
||||||
assert any(entry["event_type"] ==
|
assert any(entry["event_type"] == "dashboard.control.stop" for entry in entries)
|
||||||
"dashboard.control.stop" for entry in entries)
|
assert any(entry["event_type"] == "dashboard.control.start" for entry in entries)
|
||||||
assert any(entry["event_type"] ==
|
assert any(entry["event_type"] == "dashboard.control.kill_switch" for entry in entries)
|
||||||
"dashboard.control.start" for entry in entries)
|
assert any(entry["event_type"] == "dashboard.control.config" for entry in entries)
|
||||||
assert any(entry["event_type"] ==
|
|
||||||
"dashboard.control.kill_switch" for entry in entries)
|
|
||||||
assert any(entry["event_type"] ==
|
|
||||||
"dashboard.control.config" for entry in entries)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_dashboard_controls_emit_alerts(tmp_path) -> None:
|
async def test_dashboard_controls_emit_alerts(tmp_path) -> None:
|
||||||
|
|||||||
@@ -67,13 +67,11 @@ def test_backtest_replay_engine_runs_deterministically() -> None:
|
|||||||
engine = BacktestReplayEngine(
|
engine = BacktestReplayEngine(
|
||||||
cycles_by_pair=cycles_by_pair,
|
cycles_by_pair=cycles_by_pair,
|
||||||
available_pairs=available_pairs,
|
available_pairs=available_pairs,
|
||||||
config=BacktestConfig(trade_capital=100.0,
|
config=BacktestConfig(trade_capital=100.0, slippage_bps=5.0, execution_latency_ms=10.0),
|
||||||
slippage_bps=5.0, execution_latency_ms=10.0),
|
|
||||||
started_at=started_at,
|
started_at=started_at,
|
||||||
)
|
)
|
||||||
|
|
||||||
report = asyncio.run(engine.run(
|
report = asyncio.run(engine.run(replay_events, starting_balances={"USD": 1000.0}))
|
||||||
replay_events, starting_balances={"USD": 1000.0}))
|
|
||||||
|
|
||||||
assert report.processed_events == 3
|
assert report.processed_events == 3
|
||||||
assert report.opportunities_seen >= 0
|
assert report.opportunities_seen >= 0
|
||||||
|
|||||||
Reference in New Issue
Block a user