Docs / Validate documentation (push) Canceled after 0s
Docs / Deploy GitHub Pages (push) Canceled after 0s
CI Final Summary (AI) / AI Final Summary (push) Canceled after 0s
CI Final Summary (AI) / Push/PR event feed (push) Canceled after 0s
CI / CI Integrity and Change Classification (push) Canceled after 0s
CI / Code Quality & Tests (push) Canceled after 0s
Dependency Lock & Migration Safety / Dependency drift (lock vs pyproject) (push) Canceled after 0s
Dependency Lock & Migration Safety / Migration safety (fail-loud + version postconditions) (push) Canceled after 0s
JS Tests / Frontend JS Unit Tests (push) Canceled after 0s
Security / CodeQL Analysis (push) Canceled after 0s
Security / Trivy Vulnerability Scan (push) Canceled after 0s
Tests (OS Matrix) / Py Tests (macos-latest) (push) Canceled after 0s
Tests (OS Matrix) / Py Tests (windows-latest) (push) Canceled after 0s
CI / Extended Validation (Tier 2) (push) Canceled after 0s
CI / Heavy CI (database-provider) (push) Canceled after 0s
CI / Heavy CI (e2e) (push) Canceled after 0s
CI / Heavy CI (integration) (push) Canceled after 0s
CI / Heavy CI (model-validation) (push) Canceled after 0s
CI / Heavy CI (research-backtest) (push) Canceled after 0s
CI / Aggregate CI Results (push) Canceled after 0s
Full project import for the self-hosted code hosting (https://code.aifunny.ltd/gavindiaz/my-NexusTradingForexBot.git). Includes the live-freshness + scaler-hash fixes for the permanent STALE dashboard (tick_pipeline now_utc stamps; infer_probabilities computes model_input_hash on the actual scaled 70D tensor), the data-fetch default-path fix, the g29 web-auth test fixes, and a Chinese user manual (使用手册.md) for the web dashboard. Scratch diagnostic scripts (check*.py, contain a live web-auth token) and the .kilo/ agent-worktree directory are gitignored, not committed. Co-Authored-By: Claude Code <noreply@anthropic.com>
80 lines
2.7 KiB
Python
80 lines
2.7 KiB
Python
"""Task D reconciliation helper for PAPER accounting (tests/helpers).
|
|
|
|
Importable helper to assert equity==balance+unrealized and realized invariants.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
|
|
def assert_accounting_invariants(adapter: Any, *, strict: bool = True) -> dict[str, Any]:
|
|
"""Assert equity == balance + floating PnL within 1 cent.
|
|
|
|
Also asserts each open position's stored profit matches current tick when
|
|
available. Returns the reconcile dict for logging. Raises AssertionError
|
|
on violation (strict=True, default), otherwise returns ok=False.
|
|
"""
|
|
# prefer adapter's own reconcile if present
|
|
if hasattr(adapter, "reconcile_accounting"):
|
|
try:
|
|
return adapter.reconcile_accounting() # type: ignore[operator]
|
|
except AssertionError:
|
|
raise
|
|
except Exception as e:
|
|
if strict:
|
|
raise AssertionError(f"reconcile_accounting failed: {e}") from e
|
|
|
|
# fallback manual check against adapter attributes
|
|
balance = float(getattr(adapter, "balance", 0.0))
|
|
equity = float(getattr(adapter, "equity", 0.0))
|
|
positions = list(
|
|
getattr(adapter, "_positions", []) or getattr(adapter, "get_positions", lambda **_: [])()
|
|
)
|
|
# try floating helper
|
|
floating = None
|
|
if hasattr(adapter, "_floating_pnl"):
|
|
try:
|
|
floating = float(adapter._floating_pnl()) # type: ignore[operator]
|
|
except Exception:
|
|
floating = None
|
|
if floating is None:
|
|
floating = sum(float(getattr(p, "profit", 0.0)) for p in positions)
|
|
expected = round(balance + floating, 2)
|
|
ok = abs(equity - expected) < 0.015
|
|
info: dict[str, Any] = {
|
|
"balance": balance,
|
|
"equity": equity,
|
|
"floating_pnl": floating,
|
|
"expected_equity": expected,
|
|
"ok": ok,
|
|
"positions": len(positions),
|
|
}
|
|
if strict:
|
|
assert ok, f"equity invariant broken: {info}"
|
|
return info
|
|
|
|
|
|
def assert_realized_pnl_formula(
|
|
*,
|
|
symbol: str,
|
|
order_type: str,
|
|
price_open: float,
|
|
price_close: float,
|
|
volume: float,
|
|
contract_size: float = 100.0,
|
|
expected: float,
|
|
) -> None:
|
|
"""Check BUY=(close-open)*vol*contract, SELL=(open-close)*vol*contract."""
|
|
if str(order_type).upper() == "BUY":
|
|
calc = round(
|
|
(float(price_close) - float(price_open)) * float(volume) * float(contract_size), 2
|
|
)
|
|
else:
|
|
calc = round(
|
|
(float(price_open) - float(price_close)) * float(volume) * float(contract_size), 2
|
|
)
|
|
assert abs(calc - float(expected)) < 0.015, (
|
|
f"realized PnL mismatch: calc {calc} vs expected {expected} ({symbol} {order_type} {price_open}->{price_close} x{volume}*c{contract_size})"
|
|
)
|