From 8e53c995cd805cc6a16b05bd95cf4dd7394c5efb Mon Sep 17 00:00:00 2001 From: boris Date: Thu, 23 Apr 2026 20:22:19 -0700 Subject: [PATCH] Expose stock account accessors --- crates/fidc-core/src/strategy.rs | 22 ++++++++++++++++++++++ crates/fidc-core/src/strategy_ai.rs | 2 +- crates/fidc-core/tests/engine_hooks.rs | 8 ++++++++ docs/rqalpha-gap-roadmap.md | 8 +++++--- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/crates/fidc-core/src/strategy.rs b/crates/fidc-core/src/strategy.rs index 4577d75..c88da4c 100644 --- a/crates/fidc-core/src/strategy.rs +++ b/crates/fidc-core/src/strategy.rs @@ -104,6 +104,7 @@ pub struct OrderRuntimeView { #[derive(Debug, Clone)] pub struct PortfolioRuntimeView { + pub account_type: &'static str, pub starting_cash: f64, pub units: f64, pub cash: f64, @@ -359,6 +360,7 @@ impl StrategyContext<'_> { let cash = self.portfolio.cash(); let total_equity = self.portfolio.total_equity(); PortfolioRuntimeView { + account_type: "STOCK", starting_cash: self.portfolio.starting_cash(), units: self.portfolio.units(), cash, @@ -386,6 +388,26 @@ impl StrategyContext<'_> { self.portfolio_view() } + pub fn stock_account(&self) -> PortfolioRuntimeView { + self.portfolio_view() + } + + pub fn future_account(&self) -> Option { + None + } + + pub fn account_by_type(&self, account_type: &str) -> Option { + if account_type.eq_ignore_ascii_case("STOCK") { + Some(self.stock_account()) + } else { + None + } + } + + pub fn accounts(&self) -> BTreeMap { + BTreeMap::from([("STOCK".to_string(), self.stock_account())]) + } + pub fn frozen_cash(&self) -> f64 { self.open_orders .iter() diff --git a/crates/fidc-core/src/strategy_ai.rs b/crates/fidc-core/src/strategy_ai.rs index 0bfa161..66f0976 100644 --- a/crates/fidc-core/src/strategy_ai.rs +++ b/crates/fidc-core/src/strategy_ai.rs @@ -207,7 +207,7 @@ pub fn built_in_strategy_manual() -> StrategyAiManual { ManualFunction { name: "is_suspended/is_st_stock".to_string(), signature: "ctx.is_suspended(symbol, count)".to_string(), detail: "读取指定证券截至当前交易日最近 count 个交易日的停牌或 ST 标记,返回 bool 序列,顺序从旧到新;对应 RQAlpha 的 is_suspended/is_st_stock 数据源能力。".to_string() }, ManualFunction { name: "get_price".to_string(), signature: "ctx.get_price(symbol, start_date, end_date, \"1d\" | \"1m\" | \"tick\")".to_string(), detail: "按日期区间读取统一 PriceBar 序列。日线返回 open/high/low/close/last/volume/盘口字段;分钟或 tick 返回按 timestamp 排序的 last/bid1/ask1/volume_delta/amount_delta 映射,便于服务层转成表格或前端明细。".to_string() }, ManualFunction { name: "order/order_status/order_avg_price/order_transaction_cost".to_string(), signature: "ctx.order(order_id)".to_string(), detail: "按订单 id 查询运行时订单对象,支持已结束订单和当前挂单。返回字段包括 status、filled_quantity、unfilled_quantity、avg_price、transaction_cost、symbol、side、reason;可用便捷函数读取状态、成交均价和费用,对齐 RQAlpha Order 的核心属性。".to_string() }, - ManualFunction { name: "account/portfolio_view".to_string(), signature: "ctx.account()".to_string(), detail: "返回当前股票账户/组合运行时视图,字段包括 cash、available_cash、frozen_cash、market_value、total_value、unit_net_value、daily_pnl、daily_returns、total_returns、transaction_cost、trading_pnl、position_pnl 等;DSL 中同名字段可直接使用。".to_string() }, + ManualFunction { name: "account/portfolio_view/accounts".to_string(), signature: "ctx.account()".to_string(), detail: "返回当前股票账户/组合运行时视图,字段包括 account_type、cash、available_cash、frozen_cash、market_value、total_value、unit_net_value、daily_pnl、daily_returns、total_returns、transaction_cost、trading_pnl、position_pnl 等;DSL 中同名字段可直接使用。也可用 ctx.stock_account()、ctx.account_by_type(\"STOCK\")、ctx.accounts() 按账户类型读取;当前股票回测路径不会把 FUTURE 虚假映射成 STOCK。".to_string() }, ManualFunction { name: "deposit_withdraw/finance_repay/management_fee".to_string(), signature: "account.deposit_withdraw(amount, receiving_days=0)".to_string(), detail: "策略账户资金动作。deposit_withdraw 正数入金、负数出金;receiving_days 大于 0 时按交易日延迟到账,并保持净值口径不把外部资金流当成收益。finance_repay 正数融资、负数还款,会同步维护 cash_liabilities。set_management_fee_rate 设置结算管理费率;普通策略可覆盖 management_fee(ctx, rate) 自定义计算器,对齐 RQAlpha 管理费回调能力。".to_string() }, ManualFunction { name: "rolling_mean".to_string(), signature: "rolling_mean(\"field\", lookback)".to_string(), detail: "任意字段滚动均值,支持 volume/amount/turnover_ratio、signal_open/signal_close、benchmark_open/benchmark_close 等。任意成交量窗口推荐用它,比如 rolling_mean(\"volume\", 15)。".to_string() }, ManualFunction { name: "sma".to_string(), signature: "sma(\"field\", lookback)".to_string(), detail: "rolling_mean 的别名。任意价格均线窗口推荐用它,比如 sma(\"close\", 15)。".to_string() }, diff --git a/crates/fidc-core/tests/engine_hooks.rs b/crates/fidc-core/tests/engine_hooks.rs index c72346a..4307822 100644 --- a/crates/fidc-core/tests/engine_hooks.rs +++ b/crates/fidc-core/tests/engine_hooks.rs @@ -1342,6 +1342,7 @@ fn strategy_context_exposes_rqalpha_style_account_runtime_view() { let account = ctx.account(); + assert_eq!(account.account_type, "STOCK"); assert!((account.starting_cash - 10_000.0).abs() < 1e-6); assert!((account.frozen_cash - 600.0).abs() < 1e-6); assert!((account.available_cash - 9_400.0).abs() < 1e-6); @@ -1350,6 +1351,13 @@ fn strategy_context_exposes_rqalpha_style_account_runtime_view() { assert!((account.daily_returns - portfolio.daily_returns()).abs() < 1e-6); assert!((account.total_returns - portfolio.total_returns()).abs() < 1e-6); assert!((ctx.available_cash() - account.available_cash).abs() < 1e-6); + assert!(ctx.future_account().is_none()); + assert!(ctx.account_by_type("FUTURE").is_none()); + assert!((ctx.account_by_type("stock").unwrap().cash - account.cash).abs() < 1e-6); + assert_eq!( + ctx.accounts().keys().cloned().collect::>(), + vec!["STOCK".to_string()] + ); } #[test] diff --git a/docs/rqalpha-gap-roadmap.md b/docs/rqalpha-gap-roadmap.md index 93170bc..023dc53 100644 --- a/docs/rqalpha-gap-roadmap.md +++ b/docs/rqalpha-gap-roadmap.md @@ -83,7 +83,9 @@ current alignment pass. - [x] explicit deposit / withdraw API - [x] financing liability / repay API - [x] management-fee rate and callback parity -- [ ] multi-account stock/future segregation +- [x] stock account map/accessor surface (`accounts`, `stock_account`, + `account_by_type("STOCK")`) +- [ ] full futures account, margin, and short-position execution model ## Execution Order @@ -101,5 +103,5 @@ current alignment pass. Active implementation target: continue account parity after exposing the stock account runtime view, core Portfolio fields, deposit/withdraw, financing -liability APIs, and management-fee callbacks; next gap is multi-account -stock/future segregation. +liability APIs, management-fee callbacks, and stock account accessors; next gap +is the full futures account, margin, and short-position execution model.