Files
siloqy/prod/clean_arch/dita_v2/_gen_test.py
Codex 3d7b00e28d Snapshot PINK DITAv2 system + Sprint 0 flaw-fix verification
First commit of the previously-untracked PINK-on-DITAv2 migration system
(execution moves to the Rust kernel; policy stays on legacy DITA, so Alpha
Engine algorithmic integrity is preserved). BLUE is untouched.

Sprint 0 (safety snapshot + flaw-fix verification, MARKET single-leg scope):
- Verified Rust FSM fixes (flaws 2,4,10,11,13) by source read of lib.rs.
- Hardened 5 vacuous/guarded assertions in test_flaws.py so each flaw test
  genuinely exercises its fix. Most important: Flaw 5 now asserts capital
  moves by EXACTLY realized PnL (was entering/exiting at the same price).
- Offline suites: 533 passed, 0 failed (35 flaws + 402 kernel/accounting/
  bridge + 96 runtime/persistence/multi-exit/restart/seams).
- GATE PASS: MARKET-path-critical flaws 1,2,5 confirmed fixed + green.
- Added SPRINT0_FLAW_VERIFICATION.md report and _rust_kernel/.gitignore
  (excludes Rust target/ build artifacts).

LIMIT/partial-fill remain explicitly out of scope (MARKET-only bring-up).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 18:26:43 +02:00

1245 lines
60 KiB
Python

"""Generate the complete pink e2e test file."""
import sys
sys.path.insert(0, '/mnt/dolphinng5_predict')
fpath = '/mnt/dolphinng5_predict/prod/tests/test_pink_bingx_dita_live_e2e.py'
lines = []
def emit(s=""):
lines.append(s)
# ---- IMPORTS ----
emit('#!/usr/bin/env python3')
emit('"""PINK DITAv2 Live BingX Testnet E2E — conceptual gap coverage."""')
emit('from __future__ import annotations')
emit('import asyncio, json, os, socket, time, urllib.request')
emit('import urllib.parse')
emit('from dataclasses import dataclass')
emit('from typing import Any, Optional')
emit('import pytest')
emit('from prod.bingx.http import BingxHttpClient')
emit('from prod.bingx.config import BingxExecClientConfig, BingxEnvironment')
emit('from prod.clean_arch.dita_v2.launcher import build_launcher_bundle')
emit('from prod.clean_arch.dita_v2.contracts import (')
emit(' KernelCommandType as KC, KernelIntent as KI, TradeSide as TS,')
emit(' VenueEvent, VenueEventStatus, KernelEventKind,')
emit(' TradeStage, KernelDiagnosticCode, KernelSeverity,')
emit(' KernelOutcome, KernelTransition, TradeSlot, VenueOrder,')
emit(')')
emit('from prod.clean_arch.ports.data_feed import MarketSnapshot')
emit('E = KC')
emit('')
emit('# Force IPv4')
emit('_orig_gai = socket.getaddrinfo')
emit('def _ipv4_gai(host, port, family=0, type=0, proto=0, flags=0):')
emit(' return _orig_gai(host, port, socket.AF_INET, type, proto, flags)')
emit('socket.getaddrinfo = _ipv4_gai')
emit('')
emit('_last_finish: float = 0.0')
emit('def _throttle(min_gap: float = 3.0) -> None:')
emit(' global _last_finish')
emit(' now = __import__("time").time()')
emit(' elapsed = now - _last_finish')
emit(' if elapsed < min_gap:')
emit(' __import__("time").sleep(min_gap - elapsed)')
emit(' _last_finish = __import__("time").time()')
emit('')
# ---- HELPERS ----
emit('class VR:')
emit(' def __init__(self, symbol, positions_flat, error):')
emit(' self.symbol = symbol; self.positions_flat = positions_flat; self.error = error')
emit('')
emit('class RB:')
emit(' def __init__(self, runtime=None, config=None):')
emit(' self.runtime = runtime; self.config = config')
emit('')
emit('def _build_config(ic: float = 25000.0) -> BingxExecClientConfig:')
emit(' return BingxExecClientConfig(environment=BingxEnvironment.TESTNET,')
emit(' api_key=os.environ["BINGX_API_KEY"], secret_key=os.environ["BINGX_SECRET_KEY"],')
emit(' testnet=True, recv_window_ms=5000, default_leverage=1, initial_capital_usdt=ic)')
emit('')
emit('def _build_rb(ic: float = 25000.0, max_slots: int = 1) -> RB:')
emit(' cfg = _build_config(ic)')
emit(' b = build_launcher_bundle(venue_mode="BINGX", max_slots=max_slots, bingx_config=cfg)')
emit(' k = b.kernel; k.account.snapshot.capital = ic')
emit(' k.account.snapshot.peak_capital = ic; k.account.snapshot.equity = ic')
emit(' class Shim:')
emit(' def __init__(self, k): self.kernel = k')
emit(' async def connect(self, initial_capital=0): self.kernel.venue.connect()')
emit(' async def disconnect(self):')
emit(' try: self.kernel.venue.disconnect()')
emit(' except: pass')
emit(' return RB(runtime=Shim(k), config=cfg)')
emit('')
emit('def _inspect_outcome(r, label):')
emit(' return dict(accepted=r.accepted, state=r.state.value if r.state else "",')
emit(' diagnostic=r.diagnostic_code.value if r.diagnostic_code else "",')
emit(' severity=r.severity.value if r.severity else "",')
emit(' transitions=[(t.prev_state.value, t.next_state.value) for t in (r.transitions or ())],')
emit(' event_kinds=[e.kind.value for e in (r.emitted_events or ())],')
emit(' details=dict(r.details or {}))')
emit('')
emit('def _assert_accepted(r, label):')
emit(' info = _inspect_outcome(r, label)')
emit(' assert r.accepted, f"{label}: intent rejected diag={info[chr(34)+chr(34)]diagnostic[chr(34)+chr(34)]} state={info[chr(34)+chr(34)]state[chr(34)+chr(34)]} detail={info[chr(34)+chr(34)]details[chr(34)+chr(34)]}"')
emit('')
emit('def _assert_rejected(r, expected_diag, label):')
emit(' info = _inspect_outcome(r, label)')
emit(' assert not r.accepted, f"{label}: expected rejection but got accepted state={info[chr(34)+chr(34)]state[chr(34)+chr(34)]}"')
emit(' assert info["diagnostic"] == expected_diag, f"{label}: expected {expected_diag} got {info[chr(34)+chr(34)]diagnostic[chr(34)+chr(34)]}"')
emit('')
emit('def _check_slot_accounting(k, label):')
emit(' sc = getattr(k, "_start_cap", None)')
emit(' if sc is None: return')
emit(' trp = sum(k.slot(i).realized_pnl for i in range(k.max_slots))')
emit(' tup = sum(k.slot(i).unrealized_pnl for i in range(k.max_slots))')
emit(' expected = sc + trp + tup')
emit(' actual = k.account.snapshot.capital')
emit(' assert abs(actual - expected) < 0.01, f"{label}: acct mismatch cap={actual} exp={expected} rp={trp} upnl={tup}"')
emit('')
emit('def _check_open_orders(c, vs):')
emit(' import asyncio')
emit(' r = asyncio.run(c._request_json("GET", "/openApi/swap/v2/trade/openOrders", {"symbol": vs}, signed=True))')
emit(' data = r if isinstance(r, list) else (r.get("data") or r.get("orders") or [])')
emit(' return [o for o in data if isinstance(o, dict)]')
emit('')
emit('def _build_fresh_kernel_from_slot(slot_data, ic=25000.0):')
emit(' from prod.clean_arch.dita_v2.rust_backend import _slot_from_payload')
emit(' cfg = _build_config(ic)')
emit(' b = build_launcher_bundle(venue_mode="BINGX", max_slots=1, bingx_config=cfg)')
emit(' k = b.kernel; k.account.snapshot.capital = ic')
emit(' k.account.snapshot.peak_capital = ic; k.account.snapshot.equity = ic')
emit(' restored = _slot_from_payload(slot_data)')
emit(' k.reconcile_from_slots([restored])')
emit(' class Shim:')
emit(' def __init__(self, k): self.kernel = k')
emit(' async def connect(self, ic=0): self.kernel.venue.connect()')
emit(' async def disconnect(self):')
emit(' try: self.kernel.venue.disconnect()')
emit(' except: pass')
emit(' return RB(runtime=Shim(k), config=cfg)')
emit('')
# ---- EXISTING HELPERS ----
emit('async def _contract_rows(c):')
emit(' r = await c._request_json("GET", "/openApi/swap/v2/user/positions", {}, signed=True)')
emit(' return r if isinstance(r, list) else (r.get("data") or r.get("positions") or [])')
emit('')
emit('async def _pick_sym(k, c):')
emit(' rs = await _contract_rows(c)')
emit(' oss = {str(r.get("symbol","")).replace("-","").upper() for r in rs}')
emit(' return next((x for x in ["TRXUSDT","XRPUSDT","ADAUSDT","DOGEUSDT"] if x not in oss), "TRXUSDT")')
emit('')
emit('async def _snap(c, sym):')
emit(' pr = await c._request_json("GET", "/openApi/swap/v2/quote/price", {"symbol": sym}, signed=False)')
emit(' d = pr.get("data") or pr; rp = float(d.get("price") or d.get("lastPrice") or 0)')
emit(' return MarketSnapshot(timestamp=__import__("datetime").datetime.now(__import__("datetime").timezone.utc),')
emit(' symbol=sym, price=rp, bid=rp*0.9995, ask=rp*1.0005), sym')
emit('')
emit('async def _verify(c, vs):')
emit(' rs = await _contract_rows(c)')
emit(' tr = [r for r in rs if str(r.get("symbol","")).upper().replace("-","") == vs.replace("-","").upper()]')
emit(' ts = sum(abs(float(r.get("positionAmt",r.get("positionQty",0)) or 0)) for r in tr)')
emit(' flat = ts < 1e-8')
emit(' oos = _check_open_orders(c, vs)')
emit(' no_orders = len(oos) == 0')
emit(' err = ""')
emit(' if not flat: err += f"pos_open: {tr} "')
emit(' if not no_orders: err += f"open_orders: {oos} "')
emit(' return VR(symbol=vs, positions_flat=flat and no_orders, error=err.strip())')
emit('')
emit('def _si(k, act, tid, asset, side_str, price, size, **kw):')
emit(' ds = TS.SHORT if side_str.upper() == "SHORT" else TS.LONG')
emit(' slot_id = kw.pop("slot_id", 0)')
emit(' return k.process_intent(KI(timestamp=__import__("datetime").datetime.now(__import__("datetime").timezone.utc),')
emit(' intent_id=tid, trade_id=tid, slot_id=slot_id, asset=asset, side=ds, action=act,')
emit(' reference_price=price, target_size=size, leverage=kw.pop("leverage",1.0),')
emit(' exit_leg_ratios=kw.pop("exit_leg_ratios",(1.0,)),')
emit(' reason=kw.pop("reason",f"auto_{act.value.lower()}"), metadata=kw))')
emit('')
emit('def _flatten(k, sym, price, label, slot_id=0):')
emit(' if k.slot(slot_id).is_free(): return')
emit(' ts = int(time.time()*1000)')
emit(' _si(k, E.EXIT, f"fl{label}-{ts}", sym, "SHORT", price, 0.001, slot_id=slot_id)')
emit(' if not k.slot(slot_id).is_free():')
emit(' _si(k, E.EXIT, f"fl{label}b-{ts}", sym, "LONG", price, 0.001, slot_id=slot_id)')
emit('')
emit('async def _run(bundle, client, body_fn, label, ic):')
emit(' k = bundle.runtime.kernel')
emit(' sym = await _pick_sym(k, client)')
emit(' snap, vsym = await _snap(client, sym)')
emit(' await bundle.runtime.connect(initial_capital=ic)')
emit(' p = float(snap.price)')
emit(' try:')
emit(' for si in range(k.max_slots):')
emit(' if not k.slot(si).is_free():')
emit(' _flatten(k, sym, p*0.99 if si == 0 else p*1.005, f"{label}-pre-{si}")')
emit(' await asyncio.sleep(0.3)')
emit(' k._start_cap = k.account.snapshot.capital')
emit(' cb = k.account.snapshot.capital')
emit(' await body_fn(k, sym, p)')
emit(' ca = k.account.snapshot.capital')
emit(' assert ca > 0, f"Capital zero: {ca}"')
emit(' max_change = max(1.0, cb * 0.10)')
emit(' assert cb - ca < max_change, f"Capital shrunk beyond tolerance: {cb} -> {ca} (limit={max_change})"')
emit(' total_rp = sum(k.slot(i).realized_pnl for i in range(k.max_slots))')
emit(' if abs(total_rp) > 0.0001:')
emit(' assert abs(total_rp) < abs(cb - ca) + 0.01, f"{label}: rp={total_rp} != cap_change={cb-ca}"')
emit(' for si in range(k.max_slots):')
emit(' if not k.slot(si).is_free():')
emit(' _flatten(k, sym, p*0.99 if si == 0 else p*1.005, f"{label}-post-{si}")')
emit(' await asyncio.sleep(1.0)')
emit(' _throttle(3.0)')
emit(' return await _verify(client, vsym)')
emit(' finally:')
emit(' await bundle.runtime.disconnect()')
emit('')
# ---- BODY TEMPLATES ----
# I'll build the body functions from a structured list
bodies = {} # name -> list of code lines
def B(name, lines):
bodies[name] = lines
B("simple_entry_exit", [
'tid = f"ss-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
])
B("multi_leg_exit", [
'tid = f"ml-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.002, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(1)',
])
B("cancel_entry_order", [
'tid = f"ce-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
])
B("entry_hold_exit", [
'tid = f"eh-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(3)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
])
B("entry_exit_at_loss", [
'tid = f"el-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*1.005, 0.001); await asyncio.sleep(1)',
])
B("two_sequential_cycles", [
't1 = f"sq1-{int(time.time()*1000)}"; t2 = f"sq2-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
'_si(k, E.ENTER, t2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, t2, symbol, "SHORT", p*0.99, 0.001); await asyncio.sleep(1)',
])
B("entry_then_recover", [
'tid = f"r-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
])
B("long_entry_exit", [
'tid = f"l-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "LONG", p, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(1)',
])
B("cancel_idempotent", [
'tid = f"ci-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
])
B("double_cancel", [
'tid = f"dc-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
])
B("cancel_then_exit", [
'tid = f"ctx-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
])
B("exit_then_cancel_exit", [
'tid = f"ecx-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
])
B("exit_then_reentry", [
't1 = f"er1-{int(time.time()*1000)}"; t2 = f"er2-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
'_si(k, E.ENTER, t2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(1)',
'_si(k, E.EXIT, t2, symbol, "SHORT", p*0.99, 0.001); await asyncio.sleep(1)',
])
B("limit_cancel", [
'tid = f"lc-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p*0.9, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p*0.9, 0.001); await asyncio.sleep(1)',
])
B("x4_partial_hold_exit", [
'tid = f"x4ph-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.002, exit_leg_ratios=(0.3,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.0006, exit_leg_ratios=(0.3,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.0014, exit_leg_ratios=(0.3,1.0)); await asyncio.sleep(1)',
])
B("x4_three_leg", [
'tid = f"x4tl-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.003, exit_leg_ratios=(0.25,0.25,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.00075, exit_leg_ratios=(0.25,0.25,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.0015, exit_leg_ratios=(0.25,0.25,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.991, 0.00075, exit_leg_ratios=(0.25,0.25,1.0)); await asyncio.sleep(1)',
])
B("x4_cancel_fill_partial", [
'tid = f"x4cf-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.002, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)',
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)',
])
B("x4_rapid_three", [
"for j in range(3):",
' tid = f"x4r{j}-{int(time.time()*1000)}"',
' _si(k, E.ENTER, tid, symbol, "SHORT", p*(1-j*0.003), 0.001); await asyncio.sleep(0.5)',
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995*(1-j*0.003), 0.001); await asyncio.sleep(0.5)',
])
B("x4_diff_symbol", [
"ts = int(time.time()*1000)",
'_si(k, E.ENTER, f"x4ds1-{ts}", symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.EXIT, f"x4ds1-{ts}", "ZZZUSDT", "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("x4_alternating", [
"ts = int(time.time()*1000)",
'_si(k, E.ENTER, f"x4a1-{ts}", symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.EXIT, f"x4a1-{ts}", symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.ENTER, f"x4a2-{ts}", symbol, "LONG", p*0.995, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.EXIT, f"x4a2-{ts}", symbol, "LONG", p*1.002, 0.001); await asyncio.sleep(0.5)',
])
B("x4_multi_flatten", [
'tid = f"x4mf-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"while not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
])
B("x4_three_leg_25_50_25", [
'tid = f"x4t3-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.002, exit_leg_ratios=(0.25,0.5,1.0)); await asyncio.sleep(1)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.0005, exit_leg_ratios=(0.25,0.5,1.0)); await asyncio.sleep(0.7)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.001, exit_leg_ratios=(0.25,0.5,1.0)); await asyncio.sleep(0.7)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.991, 0.0005, exit_leg_ratios=(0.25,0.5,1.0)); await asyncio.sleep(1)',
])
B("x4_enter_exit_hold_twice", [
"for j in range(3):",
' tid = f"x4ht{j}-{int(time.time()*1000)}"',
' _si(k, E.ENTER, tid, symbol, "SHORT", p*(1-j*0.002), 0.001); await asyncio.sleep(0.5)',
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995*(1-j*0.002), 0.001); await asyncio.sleep(0.5)',
])
B("x4_cancel_then_double_exit", [
'tid = f"x4cd-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.002, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)',
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)',
])
def make_profit_loss_bodies():
for side, side_label in [("SHORT", "short"), ("LONG", "long")]:
for pl, pl_label, price_factor in [("profit", "profit", ("0.997" if side == "SHORT" else "1.003")), ("loss", "loss", ("1.003" if side == "SHORT" else "0.997"))]:
for pattern, pat_label in [("basic", "basic"), ("partial", "partial"), ("cancel", "cancel"), ("double_exit", "double_exit")]:
name = f"{pat_label}_{side_label}_{pl}"
lines = []
tid_expr = f'f"{name[:3]}-{{int(time.time()*1000)}}"'
lines.append(f'tid = {tid_expr}')
if pattern == "basic":
exit_price = f"p*{price_factor}"
lines.append(f'_si(k, E.ENTER, tid, symbol, "{side}", p, 0.001); await asyncio.sleep(0.8)')
lines.append(f'_si(k, E.EXIT, tid, symbol, "{side}", {exit_price}, 0.001); await asyncio.sleep(0.5)')
elif pattern == "partial":
exit1 = f"p*{float(price_factor) ** 1}" if "*" not in str(price_factor) else f"p*{price_factor}"
# Use different prices for two legs
if pl == "profit":
p1, p2 = ("p*0.995", "p*0.993") if side == "SHORT" else ("p*1.005", "p*1.007")
else:
p1, p2 = ("p*1.003", "p*1.005") if side == "SHORT" else ("p*0.997", "p*0.995")
lines.append('_si(k, E.ENTER, tid, symbol, "' + side + '", p, 0.002, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.8)')
lines.append(f'_si(k, E.EXIT, tid, symbol, "{side}", {p1}, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)')
lines.append(f'_si(k, E.EXIT, tid, symbol, "{side}", {p2}, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)')
elif pattern == "cancel":
lines.append(f'_si(k, E.ENTER, tid, symbol, "{side}", p, 0.001); await asyncio.sleep(0.5)')
lines.append(f'_si(k, E.CANCEL, tid, symbol, "{side}", p, 0.001); await asyncio.sleep(0.3)')
lines.append("if not k.slot(0).is_free():")
ef = f"p*{price_factor}"
lines.append(f' _si(k, E.EXIT, tid, symbol, "{side}", {ef}, 0.001); await asyncio.sleep(0.5)')
elif pattern == "double_exit":
if side == "SHORT":
p1, p2 = ("p*0.995", "p*0.993") if pl == "profit" else ("p*1.003", "p*1.005")
else:
p1, p2 = ("p*1.005", "p*1.007") if pl == "profit" else ("p*0.997", "p*0.995")
lines.append('_si(k, E.ENTER, tid, symbol, "' + side + '", p, 0.002, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.8)')
lines.append(f'_si(k, E.EXIT, tid, symbol, "{side}", {p1}, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)')
lines.append(f'_si(k, E.EXIT, tid, symbol, "{side}", {p2}, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)')
B(name, lines)
make_profit_loss_bodies()
# Triple seq
for i in range(4):
name = f"triple_seq_{i}"
B(name, [
"for j in range(3):",
f' tid = f"ts{i}_{{j}}-{{int(time.time()*1000)}}"',
' _si(k, E.ENTER, tid, symbol, "SHORT", p*(1-j*0.003), 0.001); await asyncio.sleep(0.8)',
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995*(1-j*0.003), 0.001); await asyncio.sleep(0.5)',
])
for i in range(4):
name = f"triple_seq_long_{i}"
B(name, [
"for j in range(3):",
f' tid = f"tsl{i}_{{j}}-{{int(time.time()*1000)}}"',
' _si(k, E.ENTER, tid, symbol, "LONG", p*(1+j*0.003), 0.001); await asyncio.sleep(0.8)',
' _si(k, E.EXIT, tid, symbol, "LONG", p*1.005*(1+j*0.003), 0.001); await asyncio.sleep(0.5)',
])
# Cancel reenter
for i in range(4):
name = f"cancel_reenter_{i}"
better = ["p*0.997", "p*0.994", "p*0.991", "p*0.988"][i]
B(name, [
't1 = f"cr{}a-{}".format(' + str(i) + ', int(time.time()*1000))',
't2 = f"cr{}b-{}".format(' + str(i) + ', int(time.time()*1000))',
'_si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
f'_si(k, E.ENTER, t2, symbol, "SHORT", {better}, 0.001); await asyncio.sleep(0.8)',
f'_si(k, E.EXIT, t2, symbol, "SHORT", p*{0.995 + 0.001*i:.3f}, 0.001); await asyncio.sleep(0.5)',
])
for i in range(4):
name = f"cancel_reenter_long_{i}"
better = ["p*1.003", "p*1.006", "p*1.009", "p*1.012"][i]
B(name, [
't1 = f"crl{}a-{}".format(' + str(i) + ', int(time.time()*1000))',
't2 = f"crl{}b-{}".format(' + str(i) + ', int(time.time()*1000))',
'_si(k, E.ENTER, t1, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, t1, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(0.3)',
f'_si(k, E.ENTER, t2, symbol, "LONG", {better}, 0.001); await asyncio.sleep(0.8)',
f'_si(k, E.EXIT, t2, symbol, "LONG", p*{1.005 + 0.003*(i+1):.3f}, 0.001); await asyncio.sleep(0.5)',
])
# Leg ratio variants
ratios_data = [
("leg_ratio_0", [(0.1,1.0)], 0.002, [0.0002, 0.0018]),
("leg_ratio_1", [(0.33,0.33,1.0)], 0.003, [0.001, 0.001, 0.001]),
("leg_ratio_2", [(0.5,0.5,1.0)], 0.002, [0.001, 0.001]),
("leg_ratio_3", [(0.75,1.0)], 0.002, [0.0015, 0.0005]),
("leg_ratio_4", [(0.2,0.3,0.5,1.0)], 0.004, [0.0008, 0.0012, 0.002]),
("leg_ratio_5", [(0.4,0.6,1.0)], 0.002, [0.0008, 0.0012]),
("leg_ratio_6", [(0.15,0.85,1.0)], 0.002, [0.0003, 0.0017]),
("leg_ratio_7", [(0.25,0.25,0.5,1.0)], 0.002, [0.0005, 0.0005, 0.001]),
]
for lr_name, ratios, total_sz, sizes in ratios_data:
lines = [f'tid = f"{lr_name[:4]}-{{int(time.time()*1000)}}"']
lines.append(f'_si(k, E.ENTER, tid, symbol, "SHORT", p, {total_sz}, exit_leg_ratios={ratios[0]}); await asyncio.sleep(0.8)')
prices = [0.995, 0.993, 0.991, 0.989][:len(sizes)]
for i, (sz, pr) in enumerate(zip(sizes, prices)):
lines.append(f'_si(k, E.EXIT, tid, symbol, "SHORT", p*{pr}, {sz}, exit_leg_ratios={ratios[0]}); await asyncio.sleep(0.5)')
B(lr_name, lines)
# Breakeven
for i in range(4):
B(f"breakeven_{i}", [
f'tid = f"be{i}-{{int(time.time()*1000)}}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
])
# Price-level variants
price_variants = [
("short_exit_one_pct_profit", "SHORT", "p*0.99"),
("short_exit_third_pct_profit", "SHORT", "p*0.997"),
("short_exit_third_pct_loss", "SHORT", "p*1.003"),
("short_exit_one_pct_loss", "SHORT", "p*1.01"),
("long_exit_one_pct_profit", "LONG", "p*1.01"),
("long_exit_third_pct_profit", "LONG", "p*1.003"),
("long_exit_third_pct_loss", "LONG", "p*0.997"),
("long_exit_one_pct_loss", "LONG", "p*0.99"),
]
for pn, ps, pe in price_variants:
B(pn, [
f'tid = f"{pn[:4]}-{{int(time.time()*1000)}}"',
f'_si(k, E.ENTER, tid, symbol, "{ps}", p, 0.001); await asyncio.sleep(0.8)',
f'_si(k, E.EXIT, tid, symbol, "{ps}", {pe}, 0.001); await asyncio.sleep(0.5)',
])
# Leverage
lev = [
("entry_exit_short_2x_profit", "SHORT", 2, "p*0.995"),
("entry_exit_long_2x_profit", "LONG", 2, "p*1.005"),
("entry_exit_short_3x_profit", "SHORT", 3, "p*0.995"),
("entry_exit_long_3x_profit", "LONG", 3, "p*1.005"),
("entry_exit_short_2x_loss", "SHORT", 2, "p*1.005"),
("entry_exit_long_2x_loss", "LONG", 2, "p*0.995"),
("entry_exit_short_3x_loss", "SHORT", 3, "p*1.005"),
("entry_exit_long_3x_loss", "LONG", 3, "p*0.995"),
]
for pn, ps, lv, pe in lev:
B(pn, [
f'tid = f"{pn[:4]}-{{int(time.time()*1000)}}"',
f'_si(k, E.ENTER, tid, symbol, "{ps}", p, 0.001, leverage={lv}); await asyncio.sleep(0.8)',
f'_si(k, E.EXIT, tid, symbol, "{ps}", {pe}, 0.001, leverage={lv}); await asyncio.sleep(0.5)',
])
# Size
sz = [
("entry_exit_short_2x_size", "SHORT", 0.002),
("entry_exit_long_2x_size", "LONG", 0.002),
("entry_exit_short_3x_size", "SHORT", 0.003),
("entry_exit_long_3x_size", "LONG", 0.003),
("entry_exit_short_4x_size", "SHORT", 0.004),
("entry_exit_long_4x_size", "LONG", 0.004),
("entry_exit_short_5x_size", "SHORT", 0.005),
("entry_exit_long_5x_size", "LONG", 0.005),
]
for pn, ps, s in sz:
B(pn, [
f'tid = f"{pn[:4]}-{{int(time.time()*1000)}}"',
f'_si(k, E.ENTER, tid, symbol, "{ps}", p, {s}); await asyncio.sleep(0.8)',
f'_si(k, E.EXIT, tid, symbol, "{ps}", p*0.995 if "{ps}" == "SHORT" else p*1.005, {s}); await asyncio.sleep(0.5)',
])
# Cycles
B("three_cycle_short", [
"for j in range(3):",
' tid = f"tcs{j}-{int(time.time()*1000)}"',
' _si(k, E.ENTER, tid, symbol, "SHORT", p*(1-j*0.003), 0.001); await asyncio.sleep(0.5)',
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.997*(1-j*0.003), 0.001); await asyncio.sleep(0.5)',
])
B("three_cycle_long", [
"for j in range(3):",
' tid = f"tcl{j}-{int(time.time()*1000)}"',
' _si(k, E.ENTER, tid, symbol, "LONG", p*(1+j*0.003), 0.001); await asyncio.sleep(0.5)',
' _si(k, E.EXIT, tid, symbol, "LONG", p*1.003*(1+j*0.003), 0.001); await asyncio.sleep(0.5)',
])
# Partial ratio
prs = [
("partial_ratio_0_short", "SHORT", (0.5,0.5,1.0), 0.002, ["p*0.995","p*0.993"], [0.001, 0.001]),
("partial_ratio_0_long", "LONG", (0.5,0.5,1.0), 0.002, ["p*1.005","p*1.007"], [0.001, 0.001]),
("partial_ratio_1_short", "SHORT", (0.33,0.33,1.0), 0.003, ["p*0.995","p*0.993","p*0.991"], [0.001, 0.001, 0.001]),
("partial_ratio_1_long", "LONG", (0.33,0.33,1.0), 0.003, ["p*1.005","p*1.007","p*1.009"], [0.001, 0.001, 0.001]),
("partial_ratio_2_short", "SHORT", (0.1,0.9,1.0), 0.002, ["p*0.995","p*0.993"], [0.0002, 0.0018]),
("partial_ratio_2_long", "LONG", (0.1,0.9,1.0), 0.002, ["p*1.005","p*1.007"], [0.0002, 0.0018]),
("partial_ratio_3_short", "SHORT", (0.25,0.25,0.5,1.0), 0.004, ["p*0.995","p*0.993","p*0.991"], [0.001, 0.001, 0.002]),
("partial_ratio_3_long", "LONG", (0.25,0.25,0.5,1.0), 0.004, ["p*1.005","p*1.007","p*1.009"], [0.001, 0.001, 0.002]),
]
for pn, ps, rat, tsz, exits, szs in prs:
lines = [f'tid = f"{pn[:4]}-{{int(time.time()*1000)}}"']
lines.append(f'_si(k, E.ENTER, tid, symbol, "{ps}", p, {tsz}, exit_leg_ratios={rat}); await asyncio.sleep(0.8)')
for xp, xs in zip(exits, szs):
lines.append(f'_si(k, E.EXIT, tid, symbol, "{ps}", {xp}, {xs}, exit_leg_ratios={rat}); await asyncio.sleep(0.5)')
B(pn, lines)
# Other groups
B("cross_asset_short", [
'tid = f"cas-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("cross_asset_long", [
'tid = f"cal-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "LONG", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(0.5)',
])
B("cancel_on_fill_short", [
'tid = f"cfs-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("cancel_on_fill_long", [
'tid = f"cfl-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(0.5)',
])
B("entry_quick_exit_short", [
'tid = f"eqs-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("entry_quick_exit_long", [
'tid = f"eql-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.EXIT, tid, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(0.5)',
])
B("triple_leg_exit_short", [
'tid = f"tls-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.003, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.5)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.001, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.5)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.991, 0.001, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.5)',
])
B("triple_leg_exit_long", [
'tid = f"tll-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "LONG", p, 0.003, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "LONG", p*1.005, 0.001, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.5)',
'_si(k, E.EXIT, tid, symbol, "LONG", p*1.007, 0.001, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.5)',
'_si(k, E.EXIT, tid, symbol, "LONG", p*1.009, 0.001, exit_leg_ratios=(0.33,0.33,1.0)); await asyncio.sleep(0.5)',
])
B("cancel_reenter_exit_short", [
't1 = f"cres-{int(time.time()*1000)}"; t2 = f"cres2-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.ENTER, t2, symbol, "SHORT", p*0.997, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, t2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("cancel_reenter_exit_long", [
't1 = f"crel-{int(time.time()*1000)}"; t2 = f"crel2-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t1, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, t1, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.ENTER, t2, symbol, "LONG", p*1.003, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, t2, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(0.5)',
])
B("zero_capital_safety", [
'tid = f"zcs-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
"if not k.slot(0).is_free():",
' _si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("position_survives_exit", [
'tid = f"pse-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("double_entry_prevention", [
't1 = f"dep1-{int(time.time()*1000)}"; t2 = f"dep2-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.ENTER, t2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("negative_capital_check", [
'tid = f"nec-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
])
# RECONCILE
B("reconcile_empty", [
"k.reconcile_from_slots([]); await asyncio.sleep(0.3)",
])
B("reconcile_after_entry", [
'tid = f"re-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"k.reconcile_from_slots([k.slot(0)]); await asyncio.sleep(0.3)",
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("reconcile_after_exit", [
'tid = f"rx-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
"k.reconcile_from_slots([k.slot(0)]); await asyncio.sleep(0.3)",
])
B("reconcile_after_cancel", [
'tid = f"rcn-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
"if not k.slot(0).is_free():",
' _si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"k.reconcile_from_slots([k.slot(0)]); await asyncio.sleep(0.3)",
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("reconcile_twice", [
'tid = f"rtw-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"k.reconcile_from_slots([k.slot(0)]); await asyncio.sleep(0.3)",
"k.reconcile_from_slots([k.slot(0)]); await asyncio.sleep(0.3)",
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("reconcile_then_cancel", [
'tid = f"rtc-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
"k.reconcile_from_slots([k.slot(0)]); await asyncio.sleep(0.3)",
"if not k.slot(0).is_free():",
' _si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# CHAOS
B("concurrent_enter_cancel", [
'tid = f"cc-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("rapid_alternating", [
't1 = f"ras-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.2)',
'_si(k, E.CANCEL, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.2)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
't2 = f"ral-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t2, symbol, "LONG", p, 0.001); await asyncio.sleep(0.2)',
'_si(k, E.CANCEL, t2, symbol, "LONG", p, 0.001); await asyncio.sleep(0.2)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t2, symbol, "LONG", p*1.005, 0.001); await asyncio.sleep(0.3)',
])
B("duplicate_trade_id", [
'tid = f"dt-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.ENTER, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("slot_busy_double_entry", [
't1 = f"sb1-{int(time.time()*1000)}"; t2 = f"sb2-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.ENTER, t2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("exit_on_idle_slot", [
'_si(k, E.EXIT, f"exidle-{int(time.time()*1000)}", symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'tid = f"eoi-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("cancel_on_idle_slot", [
'_si(k, E.CANCEL, f"coi-{int(time.time()*1000)}", symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'tid = f"cis-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("rapid_ten_cycle", [
"for i in range(10):",
' tid = f"rc10-{i}-{int(time.time()*1000)}"',
' _si(k, E.ENTER, tid, symbol, "SHORT", p*(1-i*0.001), 0.001); await asyncio.sleep(0.4)',
" if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995*(1-i*0.001), 0.001); await asyncio.sleep(0.4)',
" else:",
" break",
])
B("cancel_after_exit_fill", [
'tid = f"caf-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# MULTI-SLOT
B("multi_slot_enter_exit", [
't0 = f"ms0-{int(time.time()*1000)}"; t1 = f"ms1-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t0, symbol, "SHORT", p, 0.001, slot_id=0); await asyncio.sleep(0.4)',
'_si(k, E.ENTER, t1, symbol, "LONG", p, 0.001, slot_id=1); await asyncio.sleep(0.4)',
'_si(k, E.EXIT, t0, symbol, "SHORT", p*0.995, 0.001, slot_id=0); await asyncio.sleep(0.4)',
'_si(k, E.EXIT, t1, symbol, "LONG", p*1.005, 0.001, slot_id=1); await asyncio.sleep(0.4)',
])
B("multi_slot_cross_cancel", [
't0 = f"msx0-{int(time.time()*1000)}"; t1 = f"msx1-{int(time.time()*1000)}"',
'_si(k, E.ENTER, t0, symbol, "SHORT", p, 0.001, slot_id=0); await asyncio.sleep(0.3)',
'_si(k, E.ENTER, t1, symbol, "LONG", p, 0.001, slot_id=1); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, t0, symbol, "SHORT", p, 0.001, slot_id=0); await asyncio.sleep(0.3)',
'_si(k, E.CANCEL, t1, symbol, "LONG", p, 0.001, slot_id=1); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t0, symbol, "SHORT", p*0.995, 0.001, slot_id=0); await asyncio.sleep(0.3)',
"if not k.slot(1).is_free():",
' _si(k, E.EXIT, t1, symbol, "LONG", p*1.005, 0.001, slot_id=1); await asyncio.sleep(0.3)',
])
B("multi_slot_rapid_cycle", [
"for i in range(5):",
' t0 = f"msc0-{i}-{int(time.time()*1000)}"; t1 = f"msc1-{i}-{int(time.time()*1000)}"',
' _si(k, E.ENTER, t0, symbol, "SHORT", p*(1-i*0.002), 0.001, slot_id=0); await asyncio.sleep(0.3)',
' _si(k, E.ENTER, t1, symbol, "LONG", p*(1+i*0.002), 0.001, slot_id=1); await asyncio.sleep(0.3)',
' _si(k, E.EXIT, t0, symbol, "SHORT", p*0.995*(1-i*0.002), 0.001, slot_id=0); await asyncio.sleep(0.3)',
' _si(k, E.EXIT, t1, symbol, "LONG", p*1.005*(1+i*0.002), 0.001, slot_id=1); await asyncio.sleep(0.3)',
])
# REJECTION
B("reject_wrong_symbol", [
'tid = f"rs-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, "ZZZUSDT", "SHORT", 0.001, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("reject_zero_size", [
'tid = f"rz-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.0); await asyncio.sleep(0.3)',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("reject_side_mismatch_cancel", [
'tid = f"rsm-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.CANCEL, tid, symbol, "LONG", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("reject_negative_price", [
'tid = f"rn-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", -1.0, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# SNAPSHOT
B("snapshot_restore_empty", [
"s = k.snapshot(); await asyncio.sleep(0.1)",
"j = json.dumps(s); _ = json.loads(j)",
'tid = f"sre-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("snapshot_restore_mid_trade", [
'tid = f"srm-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"s = k.snapshot(); await asyncio.sleep(0.1)",
"j = json.dumps(s); _ = json.loads(j)",
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("snapshot_restore_after_cancel", [
'tid = f"src-{int(time.time()*1000)}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.5)',
'_si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"s = k.snapshot(); await asyncio.sleep(0.1)",
"j = json.dumps(s); _ = json.loads(j)",
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# LIMIT
B("limit_does_not_fill", [
'tid = "l0-" + str(int(time.time()*1000))',
"k.process_intent(KI(timestamp=__import__(\"datetime\").datetime.now(__import__(\"datetime\").timezone.utc),",
" intent_id=tid, trade_id=tid, slot_id=0, asset=symbol, side=TS.SHORT, action=E.ENTER,",
" reference_price=0.0, target_size=0.001, leverage=1.0, exit_leg_ratios=(1.0,),",
' reason="auto_zeroprice")); await asyncio.sleep(0.3)',
'tid2 = "l0r-" + str(int(time.time()*1000))',
'_si(k, E.ENTER, tid2, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("limit_immediate_fill", [
'tid = "ln-" + str(int(time.time()*1000))',
"k.process_intent(KI(timestamp=__import__(\"datetime\").datetime.now(__import__(\"datetime\").timezone.utc),",
" intent_id=tid, trade_id=tid, slot_id=0, asset=symbol, side=TS.SHORT, action=E.ENTER,",
" reference_price=p, target_size=-0.001, leverage=1.0, exit_leg_ratios=(1.0,),",
' reason="auto_negsize")); await asyncio.sleep(0.3)',
'tid2 = "lnr-" + str(int(time.time()*1000))',
'_si(k, E.ENTER, tid2, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# ===== FRESH KERNEL RECONCILE =====
B("fresh_kernel_reconcile_entry", [
'tid = "fk-" + str(int(time.time()*1000))',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"slot_data = k.slot(0).to_dict()",
"cb = k.account.snapshot.capital",
"fresh = _build_fresh_kernel_from_slot(slot_data, ic=cb)",
"k2 = fresh.runtime.kernel",
"s = k2.slot(0)",
'assert not s.is_free(), f"fresh kernel slot should not be free: {s.fsm_state}"',
'assert s.trade_id == tid, f"trade_id mismatch: {s.trade_id} vs {tid}"',
'_si(k2, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
'assert k2.slot(0).is_free(), "fresh kernel slot not free after exit"',
'assert abs(k2.account.snapshot.capital - cb) < 0.01, f"capital drift: {k2.account.snapshot.capital} vs {cb}"',
])
B("fresh_kernel_reconcile_after_cancel", [
'tid = "fkc-" + str(int(time.time()*1000))',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
'r = _si(k, E.CANCEL, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"slot_data = k.slot(0).to_dict()",
"cb = k.account.snapshot.capital",
"fresh = _build_fresh_kernel_from_slot(slot_data, ic=cb)",
"k2 = fresh.runtime.kernel",
'assert k2.slot(0).is_free(), f"cancelled slot not free: {k2.slot(0).fsm_state}"',
])
B("fresh_kernel_reconcile_after_exit", [
'tid = "fkx-" + str(int(time.time()*1000))',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
"slot_data = k.slot(0).to_dict()",
"cb = k.account.snapshot.capital",
"fresh = _build_fresh_kernel_from_slot(slot_data, ic=cb)",
"k2 = fresh.runtime.kernel",
'assert k2.slot(0).is_free(), f"closed slot not free: {k2.slot(0).fsm_state}"',
'assert k2.slot(0).closed, "slot should be marked closed"',
'assert abs(k2.account.snapshot.capital - cb) < 0.01, f"capital drift: {k2.account.snapshot.capital} vs {cb}"',
])
B("fresh_kernel_reconcile_partial_exit", [
'tid = "fkp-" + str(int(time.time()*1000))',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.002, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.5)',
"slot_data = k.slot(0).to_dict()",
"cb = k.account.snapshot.capital",
"fresh = _build_fresh_kernel_from_slot(slot_data, ic=cb)",
"k2 = fresh.runtime.kernel",
"s = k2.slot(0)",
'assert not s.is_free(), f"partial-exit slot not free: {s.fsm_state}"',
'assert s.realized_pnl != 0 or s.size > 0, "partial-exit slot should have remaining position or realized PnL"',
'_si(k2, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.001, exit_leg_ratios=(1.0,)); await asyncio.sleep(0.5)',
'assert k2.slot(0).is_free(), "slot not free after final exit on fresh kernel"',
])
# ===== CROSS-SLOT PORTFOLIO =====
B("cross_slot_portfolio_short_long", [
't0 = "psl0-" + str(int(time.time()*1000))',
't1 = "psl1-" + str(int(time.time()*1000))',
"cb = k.account.snapshot.capital",
'_si(k, E.ENTER, t0, symbol, "SHORT", p, 0.001, slot_id=0); await asyncio.sleep(0.4)',
'_si(k, E.ENTER, t1, symbol, "LONG", p, 0.001, slot_id=1); await asyncio.sleep(0.4)',
'assert not k.slot(0).is_free(), "slot 0 should be open"',
'assert not k.slot(1).is_free(), "slot 1 should be open"',
"rp0 = k.slot(0).realized_pnl; up0 = k.slot(0).unrealized_pnl",
"rp1 = k.slot(1).realized_pnl; up1 = k.slot(1).unrealized_pnl",
"expected = cb + rp0 + up0 + rp1 + up1",
"actual = k.account.snapshot.capital",
'assert abs(actual - expected) < 0.01, f"portfolio misalignment: cap={actual} exp={expected} rp0={rp0} up0={up0} rp1={rp1} up1={up1}"',
'_si(k, E.EXIT, t0, symbol, "SHORT", p*0.995, 0.001, slot_id=0); await asyncio.sleep(0.4)',
'assert k.slot(0).is_free(), "slot 0 should be free after exit"',
'_si(k, E.EXIT, t1, symbol, "LONG", p*1.005, 0.001, slot_id=1); await asyncio.sleep(0.4)',
'assert k.slot(1).is_free(), "slot 1 should be free after exit"',
])
# ===== KERNEL OUTCOME INSPECTION =====
B("outcome_inspect_entry", [
'tid = "oi-" + str(int(time.time()*1000))',
'r = _si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"_assert_accepted(r, 'entry')",
"info = _inspect_outcome(r, 'entry')",
'assert r.accepted, f"entry not accepted: {info}"',
'assert r.trade_id == tid, f"trade_id mismatch: {r.trade_id} vs {tid}"',
'assert r.slot_id == 0, f"slot_id: {r.slot_id}"',
'assert len(info["transitions"]) > 0, f"no transitions in outcome: {info}"',
'assert info["diagnostic"] == "OK", f"diagnostic not OK: {info}"',
'r2 = _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
"_assert_accepted(r2, 'exit')",
'info2 = _inspect_outcome(r2, "exit")',
'assert len(info2["transitions"]) > 0, f"no exit transitions: {info2}"',
'assert info2["diagnostic"] == "OK", f"exit diagnostic: {info2}"',
])
B("outcome_inspect_rejection", [
'tid = "or-" + str(int(time.time()*1000))',
'tid2 = "or2-" + str(int(time.time()*1000))',
'r1 = _si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"_assert_accepted(r1, 'first entry')",
'r2 = _si(k, E.ENTER, tid2, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"_assert_rejected(r2, 'SLOT_BUSY', 'double entry')",
"info = _inspect_outcome(r2, 'double entry')",
'assert not r2.accepted, f"second entry should be rejected: {info}"',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
B("outcome_inspect_exit_on_idle", [
'tid = "oei-" + str(int(time.time()*1000))',
'r = _si(k, E.EXIT, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"_assert_rejected(r, 'INVALID_FSM_TRANSITION', 'exit on idle')",
"info = _inspect_outcome(r, 'exit on idle')",
'assert not r.accepted, f"exit on idle should be rejected: {info}"',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# ===== EVENT DEDUP =====
B("dedup_duplicate_fill_event", [
'tid = "dd-" + str(int(time.time()*1000))',
'r = _si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"_assert_accepted(r, 'entry')",
"sl = k.slot(0)",
"ao = sl.active_entry_order if sl.active_entry_order else sl.active_exit_order",
"if ao:",
" dup = VenueEvent(",
" timestamp=__import__(\"datetime\").datetime.now(__import__(\"datetime\").timezone.utc),",
' event_id="dedup-test-99999",',
" trade_id=tid, slot_id=0,",
" kind=KernelEventKind.FULL_FILL,",
" status=VenueEventStatus.FILLED,",
" venue_order_id=ao.venue_order_id,",
" venue_client_id=ao.venue_client_id,",
" side=sl.side,",
" asset=symbol,",
" price=p,",
" size=0.001, filled_size=0.001, remaining_size=0.0,",
' reason="dedup_test",',
" )",
" r2 = k.on_venue_event(dup)",
" _assert_accepted(r2, 'dedup_fill')",
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# ===== FILL-PRICE DIVERGENCE =====
B("fill_price_divergence_1pct", [
'tid = "fd-" + str(int(time.time()*1000))',
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"sl = k.slot(0)",
"ao = sl.active_entry_order if sl.active_entry_order else sl.active_exit_order",
"if ao and str(sl.fsm_state) not in ('IDLE', 'CLOSED'):",
" divergent_price = p * 1.01",
" div_event = VenueEvent(",
" timestamp=__import__(\"datetime\").datetime.now(__import__(\"datetime\").timezone.utc),",
' event_id="divergence-test",',
" trade_id=tid, slot_id=0,",
" kind=KernelEventKind.FULL_FILL,",
" status=VenueEventStatus.FILLED,",
' venue_order_id=ao.venue_order_id if ao else "",',
' venue_client_id=ao.venue_client_id if ao else "",',
" side=sl.side,",
" asset=symbol,",
" price=divergent_price,",
" size=0.001, filled_size=0.001, remaining_size=0.0,",
' reason="divergence_test",',
" )",
" k.on_venue_event(div_event); await asyncio.sleep(0.3)",
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# ===== NEGATIVE CAPITAL =====
B("neg_cap_entry_rejected", [
'tid = "nc-" + str(int(time.time()*1000))',
"k.account.snapshot.capital = 0.0",
'r = _si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"info = _inspect_outcome(r, 'neg_cap')",
"k.account.snapshot.capital = 25000.0",
'_si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
'_si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
])
# ===== CROSS-SAMPLE: new patterns on old shapes =====
B("cross_sample_basic_entry_exit_outcome", [
'tid = "cs-" + str(int(time.time()*1000))',
"cb = k.account.snapshot.capital; k._start_cap = cb",
'r1 = _si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.8)',
"_assert_accepted(r1, 'cs_entry')",
"_check_slot_accounting(k, 'cs_after_entry')",
'r2 = _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
"_assert_accepted(r2, 'cs_exit')",
"_check_slot_accounting(k, 'cs_after_exit')",
"ca = k.account.snapshot.capital",
"max_change = max(1.0, cb * 0.10)",
'assert cb - ca < max_change, f"cs: cap shrunk {cb} -> {ca}"',
])
B("cross_sample_cancel_reenter_outcome", [
't1 = "csc-" + str(int(time.time()*1000))',
't2 = "csc2-" + str(int(time.time()*1000))',
"cb = k.account.snapshot.capital; k._start_cap = cb",
'r1 = _si(k, E.ENTER, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"_assert_accepted(r1, 'cs_cancel_entry')",
'r2 = _si(k, E.CANCEL, t1, symbol, "SHORT", p, 0.001); await asyncio.sleep(0.3)',
"if not k.slot(0).is_free():",
' _si(k, E.EXIT, t1, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.3)',
"_check_slot_accounting(k, 'cs_after_cancel')",
'assert k.slot(0).is_free(), "slot should be free after cancel"',
'r3 = _si(k, E.ENTER, t2, symbol, "SHORT", p*0.997, 0.001); await asyncio.sleep(0.8)',
"_assert_accepted(r3, 'cs_reenter')",
"_check_slot_accounting(k, 'cs_after_reenter')",
'r4 = _si(k, E.EXIT, t2, symbol, "SHORT", p*0.995, 0.001); await asyncio.sleep(0.5)',
"_assert_accepted(r4, 'cs_reenter_exit')",
"_check_slot_accounting(k, 'cs_after_reenter_exit')",
])
B("cross_sample_multi_leg_outcome", [
'tid = "csm-" + str(int(time.time()*1000))',
"cb = k.account.snapshot.capital; k._start_cap = cb",
'r = _si(k, E.ENTER, tid, symbol, "SHORT", p, 0.002, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.8)',
"_assert_accepted(r, 'cs_ml_entry')",
'r = _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.4)',
"_assert_accepted(r, 'cs_ml_leg1')",
"_check_slot_accounting(k, 'cs_ml_after_leg1')",
'r = _si(k, E.EXIT, tid, symbol, "SHORT", p*0.993, 0.001, exit_leg_ratios=(0.5,1.0)); await asyncio.sleep(0.4)',
"_assert_accepted(r, 'cs_ml_leg2')",
"_check_slot_accounting(k, 'cs_ml_after_leg2')",
])
B("cross_sample_leverage_tight_bounds", [
'tid = "csl-" + str(int(time.time()*1000))',
"cb = k.account.snapshot.capital; k._start_cap = cb",
'r_ent = _si(k, E.ENTER, tid, symbol, "SHORT", p, 0.001, leverage=2); await asyncio.sleep(0.8)',
"_assert_accepted(r_ent, 'cs_lev_entry')",
"_check_slot_accounting(k, 'cs_lev_after_entry')",
'r_ex = _si(k, E.EXIT, tid, symbol, "SHORT", p*0.995, 0.001, leverage=2); await asyncio.sleep(0.5)',
"_assert_accepted(r_ex, 'cs_lev_exit')",
"_check_slot_accounting(k, 'cs_lev_after_exit')",
"ca = k.account.snapshot.capital",
"max_change = max(1.0, cb * 0.10)",
'assert cb - ca < max_change, f"cs_lev: cap shrunk {cb} -> {ca}"',
])
# ---- BUILD SCENARIOS LIST ----
emit("# ============================================================")
emit("# SCENARIOS")
emit("# ============================================================")
emit("SCENARIOS = [")
for name in sorted(bodies.keys()):
emit(f' pytest.param("{name}", _body_{name}, id="{name}"),')
emit("]")
emit("")
# ---- FIXTURE + TEST ----
emit("@pytest.fixture(scope=\"session\")")
emit("def _live_client():")
emit(" return BingxHttpClient(_build_config())")
emit("")
emit("")
emit("@pytest.mark.parametrize(\"name,body_fn\", SCENARIOS)")
emit("def test_pink_ditav2(_live_client, name, body_fn) -> None:")
emit(" bundle = _build_rb()")
emit(" ic = bundle.runtime.kernel.account.snapshot.capital")
emit(" r = asyncio.run(_run(bundle, _live_client, body_fn, name, ic))")
emit(" assert r.positions_flat, f\"{name}: {r.error}\"")
# ---- WRITE BODY FUNCTIONS ----
# Build the full file: header + helpers + body functions + scenarios + fixture/test
header = "\n".join(lines)
body_funcs = []
for name, blines in bodies.items():
body_funcs.append(f"async def _body_{name}(k, symbol, p):")
for bl in blines:
body_funcs.append(f" {bl}")
body_funcs.append("")
full = header + "\n".join(body_funcs) + "\n\n" + header[header.rindex("# =="):]
# Actually let me just assemble properly
# Split header at the body section comment
body_section_header = "# ============================================================\n# SCENARIO BODIES\n# Each receives (k, symbol, p) and exercises a slice of the FSM.\n# ============================================================\n\n"
all_body_text = ""
for name, blines in bodies.items():
all_body_text += f"async def _body_{name}(k, symbol, p):\n"
for bl in blines:
if bl.startswith(" "):
all_body_text += bl + "\n"
else:
all_body_text += " " + bl + "\n"
all_body_text += "\n"
# Find the pre-body section (imports + helpers)
body_start_idx = header.index("# SCENARIO BODIES")
pre_body = header
full_text = pre_body + all_body_text + """
# ============================================================
# SCENARIOS
# ============================================================
SCENARIOS = [
""" + "\n".join([f' pytest.param("{n}", _body_{n}, id="{n}"),' for n in sorted(bodies.keys())]) + """
]
@pytest.fixture(scope="session")
def _live_client():
return BingxHttpClient(_build_config())
@pytest.mark.parametrize("name,body_fn", SCENARIOS)
def test_pink_ditav2(_live_client, name, body_fn) -> None:
bundle = _build_rb()
ic = bundle.runtime.kernel.account.snapshot.capital
r = asyncio.run(_run(bundle, _live_client, body_fn, name, ic))
assert r.positions_flat, f"{name}: {r.error}"
"""
with open(fpath, 'w') as f:
f.write(full_text)
import py_compile
try:
py_compile.compile(fpath, doraise=True)
print(f"Compiles OK. {len(bodies)} scenarios")
except py_compile.PyCompileError as e:
print(f"Compile error: {e}")
# Show the broken area
import traceback
traceback.print_exc()