feat: named live books; start selected_2026_09 (26 strategies)
A live book is a cohort of strategies, each with its own account, started on one date with one capital and a flat fee per order (trader.LIVE_BOOKS). The original book keeps its state in data/; a named book in data/books/<book>/. The monitor runs every book; auto/status/log/compare/ replay take --book. A fresh account opens on the book's first session. selected_2026_09: US $10,000 and $1 per order from 2026-09-25, CN ¥50,000 and ¥5 per order from 2026-09-28 (the first CN session after the choice). Strategies beat their benchmark in the Apr-Sep 2026 point-in-time replay and passed a 10-year PIT backtest (US Sharpe >= 0.6, MaxDD > -50%; CN Sharpe >= 0.2, CAGR > 0), no daily variants, at most two frequencies per factor signal, plus the three 2026-09 research strategies. bridge.py live --book and bridge.py books feed a book selector on the live page (/api/strategies/live?book=, /api/strategies/live/books). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
30
bridge.py
30
bridge.py
@@ -23,9 +23,13 @@ import metrics
|
||||
from backtest_runner import benchmark_curve, run_market
|
||||
from research.permanent_yearly import equity_with_cashflows
|
||||
from trader import (
|
||||
LIVE_BOOKS,
|
||||
LIVE_EXCLUDED_STRATEGIES,
|
||||
MARKET_FEE_TIERED,
|
||||
MONITOR_CAPITAL,
|
||||
STRATEGY_REGISTRY,
|
||||
book_dir,
|
||||
book_strategies,
|
||||
convert_quote_currency,
|
||||
strategy_data_market,
|
||||
strategy_supports_market,
|
||||
@@ -863,8 +867,10 @@ def cmd_live(args: argparse.Namespace) -> None:
|
||||
"""
|
||||
market = args.market
|
||||
prefix = f"trader_{market}_"
|
||||
state_files = sorted(glob(os.path.join("data", f"{prefix}*.json")))
|
||||
book = args.book or None
|
||||
state_files = sorted(glob(os.path.join(book_dir(book), f"{prefix}*.json")))
|
||||
wanted = args.strategy
|
||||
in_book = set(book_strategies(book, market)) if book else None
|
||||
|
||||
panels = _load_panels({market, "etfs"})
|
||||
bench_ticker, bench_label = LIVE_BENCHMARK[market]
|
||||
@@ -885,6 +891,9 @@ def cmd_live(args: argparse.Namespace) -> None:
|
||||
if strategy_name in LIVE_EXCLUDED_STRATEGIES or not strategy_supports_market(strategy_name, market):
|
||||
_log(f" Skipping {strategy_name}: not a live strategy in the {market.upper()} book")
|
||||
continue
|
||||
if in_book is not None and strategy_name not in in_book:
|
||||
_log(f" Skipping {strategy_name}: no longer in book {book}")
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(path) as f:
|
||||
@@ -1018,6 +1027,18 @@ def cmd_live(args: argparse.Namespace) -> None:
|
||||
json.dump(_sanitize_for_json(results), sys.stdout, default=str)
|
||||
|
||||
|
||||
def cmd_books() -> None:
|
||||
"""Live books: the original book first, then the named ones (newest last)."""
|
||||
books = [{"id": "", "label": "全部策略(2026-04 起回放)", "startDate": None,
|
||||
"capital": MONITOR_CAPITAL, "feePerOrder": None,
|
||||
"strategies": {m: book_strategies(None, m) for m in ("us", "cn")}}]
|
||||
for book_id, cfg in LIVE_BOOKS.items():
|
||||
books.append({"id": book_id, "label": cfg["label"], "startDate": cfg["start"],
|
||||
"capital": cfg["capital"], "feePerOrder": cfg["fee_per_order"],
|
||||
"strategies": {m: book_strategies(book_id, m) for m in ("us", "cn")}})
|
||||
json.dump(books, sys.stdout)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# CLI
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -1043,6 +1064,11 @@ def main() -> None:
|
||||
live_parser = subparsers.add_parser("live", help="Read live trader states")
|
||||
live_parser.add_argument("--market", default="us", choices=["us", "cn"])
|
||||
live_parser.add_argument("--strategy", default=None, help="Filter to specific strategy")
|
||||
live_parser.add_argument("--book", default="", choices=["", *LIVE_BOOKS],
|
||||
help="Named live book (default: the original book)")
|
||||
|
||||
# books
|
||||
subparsers.add_parser("books", help="List live books")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -1052,6 +1078,8 @@ def main() -> None:
|
||||
cmd_backtest(args)
|
||||
elif args.command == "live":
|
||||
cmd_live(args)
|
||||
elif args.command == "books":
|
||||
cmd_books()
|
||||
else:
|
||||
parser.print_help(sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user