Skip to content

Commit b7064b4

Browse files
committed
feat: execute CLI command — validates full execution chain
Adds 'python main.py execute' which runs the complete chain: Data → Factors → Signal → PortfolioOrchestrator → ExecutionEngine Validates that the execution layer is wired end-to-end: - Signal converted to target positions - Rebalance creates orders - Fills update positions - Summary output with PnL 1162 passed (all existing)
1 parent f63a4c8 commit b7064b4

1 file changed

Lines changed: 73 additions & 0 deletions

File tree

main.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,72 @@ def cmd_screen(args) -> int:
840840
return 0
841841

842842

843+
def cmd_execute(args) -> int:
844+
"""Execute full pipeline: factors -> signal -> orders -> fills -> positions."""
845+
config = load_config(_resolve_config_path(args.config))
846+
847+
print("Loading data...")
848+
prices, returns, benchmark, metadata, financials, turnover = _load_data(
849+
config, use_baostock=args.use_baostock
850+
)
851+
print(f" Data: {len(prices)} days, {len(prices.columns)} assets")
852+
853+
print("Computing factors...")
854+
processed_factors, ic_results, sector_map, fin_unstacked = _compute_factors(
855+
prices, returns, financials, metadata, turnover, config=config,
856+
)
857+
858+
print("Generating signal...")
859+
signal = _generate_signal(config, processed_factors, returns, prices=prices, volume=turnover)
860+
861+
print("Setting up execution engine...")
862+
from quant_platform.execution.engine import ExecutionEngine, OrderSide
863+
from quant_platform.strategy.multi_strategy import MultiStrategyManager, StrategyConfig
864+
from quant_platform.strategy.portfolio_orchestrator import PortfolioOrchestrator
865+
866+
ms = MultiStrategyManager(total_capital=1_000_000)
867+
strat_id = ms.add_strategy(StrategyConfig(
868+
name="test_strat", optimizer=config.portfolio.optimizer,
869+
allocation_pct=1.0, is_active=True,
870+
))
871+
orchestrator = PortfolioOrchestrator(ms)
872+
873+
# Get latest prices
874+
last_prices = prices.iloc[-1].to_dict()
875+
orchestrator._last_prices.update(last_prices)
876+
877+
last_date = str(prices.index[-1])[:10]
878+
print(f"Processing signal for {last_date}...")
879+
orchestrator.on_signal(last_date, signal, strategy_id=strat_id)
880+
881+
print("Executing rebalance...")
882+
orders = orchestrator.rebalance()
883+
print(f" Created {len(orders)} orders")
884+
885+
print("Processing fills...")
886+
orchestrator.process_fills(last_prices)
887+
888+
summary = orchestrator.portfolio_summary()
889+
print()
890+
print("=" * 70)
891+
print(" EXECUTION RESULT")
892+
print("=" * 70)
893+
print(f" Date: {last_date}")
894+
print(f" Positions: {summary['n_positions']}")
895+
print(f" Cash: {summary['cash_available']:,.2f}")
896+
print(f" Position Val: {summary['positions_value']:,.2f}")
897+
print(f" Unrealized PnL:{summary['unrealized_pnl']:+,.2f}")
898+
print(f" Realized PnL: {summary['realized_pnl']:+,.2f}")
899+
print(f" Total PnL: {summary['total_pnl']:+,.2f}")
900+
print(f" Alerts: {summary['alerts']}")
901+
print("-" * 70)
902+
for p in summary['positions'][:10]:
903+
print(f" {p['ticker']:<8} {p['quantity']:>5} @ {p['avg_cost']:<8.2f} = {p['market_value']:>10.2f} PnL:{p['unrealized_pnl']:>+8.2f}")
904+
if len(summary['positions']) > 10:
905+
print(f" ... and {len(summary['positions']) - 10} more")
906+
print("=" * 70)
907+
return 0
908+
843909
def cmd_config(args) -> int:
844910
"""Manage configuration versions: list, show, diff, rollback."""
845911
from quant_platform.utils.version_manager import VersionManager
@@ -1297,6 +1363,11 @@ def main() -> int:
12971363
la_parser.add_argument("--use-baostock", action="store_true",
12981364
help="Use Baostock real data")
12991365

1366+
# execute
1367+
exec_parser = subparsers.add_parser("execute", help="Full pipeline: factors -> signal -> orders -> fills")
1368+
exec_parser.add_argument("--config", "-c", type=str, default=None, help="Config path")
1369+
exec_parser.add_argument("--use-baostock", action="store_true", help="Use Baostock data")
1370+
13001371
# profile
13011372
profile_parser = subparsers.add_parser("profile", help="Profile pipeline performance")
13021373
profile_parser.add_argument("--config", "-c", type=str, default=None, help="Config path")
@@ -1329,6 +1400,8 @@ def main() -> int:
13291400
return cmd_walkforward(args)
13301401
elif args.command == "screen":
13311402
return cmd_screen(args)
1403+
elif args.command == "execute":
1404+
return cmd_execute(args)
13321405
elif args.command == "config":
13331406
return cmd_config(args)
13341407
elif args.command == "profile":

0 commit comments

Comments
 (0)