【平台使用】初上手问题反馈
由bqfmyxm1创建,最终由bqfmyxm1 被浏览 2 用户
我正在使用标普500的数据写一个简单的动量因子策略,运行时一直打印以下日志:\n
问题一
日志 103 条 ▼
[2026-03-18 15:40:22] INFO: bigtrader.v35 开始运行 ..[2026-03-18 15:40:22] INFO: pybacktest run 2020-12-31 ~ 2024-12-31, , equity, instruments=501[2026-03-18 15:40:22] INFO: bigtrader module V2.2.0[2026-03-18 15:40:22] INFO: bigtrader engine v0.1.0.post9+g6d7300d 2026-02-10[2026-03-18 15:40:23] INFO: pybacktest read history data done, run backtest ...order_target_percent: price is null for 'NVDA.O' at '2020-12-31 15:00:00'
order_target_percent: price is null for 'BBWI.N' at '2020-12-31 15:00:00'
order_target_percent: price is null for 'MRNA.O' at '2020-12-31 15:00:00'
order_target_percent: price is null for 'ETSY.O' at '2020-12-31 15:00:00'
order_target_percent: price is null for 'ENPH.O' at '2020-12-31 15:00:00'
order_target_percent: price is null for 'NVDA.O' at '2021-01-04 15:00:00'
order_target_percent: price is null for 'MRNA.O' at '2021-01-04 15:00:00'
order_target_percent: price is null for 'ETSY.O' at '2021-01-04 15:00:00'
order_target_percent: price is null for 'GNRC.N' at '2021-01-04 15:00:00'
order_target_percent: price is null for 'ENPH.O' at '2021-01-04 15:00:00'
order_target_percent: price is null for 'NVDA.O' at '2021-01-05 15:00:00'
order_target_percent: price is null for 'BBWI.N' at '2021-01-05 15:00:00'
order_target_percent: price is null for 'MRNA.O' at '2021-01-05 15:00:00'
order_target_percent: price is null for 'ETSY.O' at '2021-01-05 15:00:00'
order_target_percent: price is null for 'ENPH.O' at '2021-01-05 15:00:00'
order_target_percent: price is null for 'BBWI.N' at '2021-01-06 15:00:00'
order_target_percent: price is null for 'MRNA.O' at '2021-01-06 15:00:00'
order_target_percent: price is null for 'ETSY.O' at '2021-01-06 15:00:00'
order_target_percent: price is null for 'GNRC.N' at '2021-01-06 15:00:00'
order_target_percent: price is null for 'ENPH.O' at '2021-01-06 15:00:00'
我的代码如下:\n
import os
from bigmodule import M
import dai
# ────────────────────────────────────────────────
# 计算经典 12-1 动量(过去252日收益 - 过去21日收益)
# ────────────────────────────────────────────────
df = dai.query("""
WITH sp500_components AS (
-- 历史标普500成分股 + 有效期 carry forward
SELECT
member_code AS instrument,
date AS start_date,
LEAD(date, 1, '2099-12-31') OVER (PARTITION BY member_code ORDER BY date) AS end_date
FROM us_stock_index_component
WHERE name = '标准普尔500指数'
AND date <= '2024-12-31'
),
prices AS (
SELECT
b.date,
b.instrument,
b.close,
LAG(b.close, 21) OVER (PARTITION BY b.instrument ORDER BY b.date) AS close_21d_ago,
LAG(b.close, 252) OVER (PARTITION BY b.instrument ORDER BY b.date) AS close_252d_ago
FROM us_stock_bar1d b
INNER JOIN sp500_components c
ON b.instrument = c.instrument
AND b.date >= c.start_date
AND b.date < c.end_date
WHERE b.date BETWEEN '2020-01-01' AND '2024-12-31'
),
momentum AS (
SELECT
date,
instrument,
CASE
WHEN close_21d_ago > 0 AND close_252d_ago > 0
AND close_21d_ago IS NOT NULL
AND close_252d_ago IS NOT NULL
THEN (close / close_252d_ago - 1) - (close / close_21d_ago - 1)
ELSE NULL
END AS score -- mom_12_1
FROM prices
)
SELECT
date,
instrument,
score
FROM momentum
WHERE score IS NOT NULL
ORDER BY date, score DESC, instrument
""").df()
def initialize(context):
from bigtrader.finance.commission import PerOrder
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
context.hold_count = 5
context.weight = 1.0 / context.hold_count
context.df = df
def handle_data(context, data):
# 当前日期字符串
dt_str = data.current_dt.strftime("%Y-%m-%d")
# 取出当天所有股票的 score,按降序已排好
current_df = context.df[context.df["date"] == dt_str]
if current_df.empty:
return
# 取前 hold_count 只(已按 score DESC 排序)
to_hold_df = current_df.head(context.hold_count)
to_hold_instruments = set(to_hold_df["instrument"])
# -----------------------
# 卖出:不在新列表里的全部清仓
# -----------------------
current_positions = context.get_account_positions()
for instrument in list(current_positions.keys()):
if instrument not in to_hold_instruments:
context.order_target(instrument, 0)
# -----------------------
# 买入/调整:目标等权
# -----------------------
for instrument in to_hold_instruments:
context.order_target_percent(instrument, context.weight)
# 回测引擎调用
m5 = M.bigtrader.v35(
data=df, # 传入预计算好的 df
initialize=initialize,
handle_data=handle_data,
capital_base=1000000,
frequency="daily",
order_price_field_buy="open",
order_price_field_sell="close",
m_cached=True,
)
我理解order_target_percent这个函数就是按照order_price_field_buy设置的价格买入context.weight比例的指定标的。不太明白为啥会出现这个问题。
问题二
我搞了个可视化版本的,但是又出现了新的错误
from bigmodule import M, I
# <aistudiograph>
# @param(id="m3", name="initialize")
# 交易引擎:初始化函数,只执行一次
def m3_initialize_bigquant_run(context):
from bigtraderv1.finance.commission import PerOrder
# 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0008, min_cost=5))
context.target_hold_count = 5
context.weight = 1.0 / context.target_hold_count
# @param(id="m3", name="before_trading_start")
# 交易引擎:每个单位时间开盘前调用一次。
def m3_before_trading_start_bigquant_run(context, data):
# 盘前处理,订阅行情等
pass
# @param(id="m3", name="handle_tick")
# 交易引擎:tick数据处理函数,每个tick执行一次
def m3_handle_tick_bigquant_run(context, tick):
pass
# @param(id="m3", name="handle_data")
def m3_handle_data_bigquant_run(context, data):
import pandas as pd
# 下一个交易日不是调仓日,则不生成信号
if not context.rebalance_period.is_signal_date(data.current_dt.date()):
return
# 从传入的数据 context.data 中读取今天的信号数据这个
today_df = context.data[context.data["date"] == str(data.current_dt.date())]
# 卖出不在目标持有列表中的股票
for instrument in sorted(set(context.get_account_positions().keys()) - set(today_df["instrument"])):
context.order_target_percent(instrument, 0)
# 买入目标持有列表中的股票
for i, x in today_df.iterrows():
context.order_target_percent(x.instrument, context.weight)
# @param(id="m3", name="handle_trade")
# 交易引擎:成交回报处理函数,每个成交发生时执行一次
def m3_handle_trade_bigquant_run(context, trade):
pass
# @param(id="m3", name="handle_order")
# 交易引擎:委托回报处理函数,每个委托变化时执行一次
def m3_handle_order_bigquant_run(context, order):
pass
# @param(id="m3", name="after_trading")
# 交易引擎:盘后处理函数,每日盘后执行一次
def m3_after_trading_bigquant_run(context, data):
pass
# @module(position="-251,-76", comment="""""", comment_collapsed=True)
m1 = M.dai_sql.v1(
sql="""WITH sp500_components AS (
-- 标普500成分股 + 生效区间
SELECT
member_code AS instrument,
date AS start_date,
LEAD(date, 1, '2099-12-31') OVER (
PARTITION BY member_code
ORDER BY date
) AS end_date
FROM us_stock_index_component
WHERE name = '标准普尔500指数'
),
prices AS (
-- 价格 + 21日 / 252日滞后
SELECT
b.date,
b.instrument,
b.close,
LAG(b.close, 21) OVER (
PARTITION BY b.instrument
ORDER BY b.date
) AS close_21d_ago,
LAG(b.close, 252) OVER (
PARTITION BY b.instrument
ORDER BY b.date
) AS close_252d_ago
FROM us_stock_bar1d b
INNER JOIN sp500_components c
ON b.instrument = c.instrument
AND b.date >= c.start_date
AND b.date < c.end_date
),
momentum AS (
-- 12-1 动量(排除最近1个月)
SELECT
date,
instrument,
CASE
WHEN close_21d_ago > 0
AND close_252d_ago > 0
AND close_21d_ago IS NOT NULL
AND close_252d_ago IS NOT NULL
THEN (close / close_252d_ago - 1)
- (close / close_21d_ago - 1)
ELSE NULL
END AS score
FROM prices
),
ranked AS (
-- 每天按动量排序
SELECT
date,
instrument,
score,
ROW_NUMBER() OVER (
PARTITION BY date
ORDER BY score DESC
) AS rank
FROM momentum
WHERE score IS NOT NULL
)
-- 只取前5
SELECT
date,
instrument,
score
FROM ranked
WHERE rank <= 5
ORDER BY date, rank""",
extract_data=False,
m_name="""m1"""
)
# @module(position="-259,54", comment="""""", comment_collapsed=True)
m2 = M.extract_data_dai.v20(
sql=m1.data,
start_date="""2020-01-01""",
start_date_bound_to_trading_date=True,
end_date="""2026-03-01""",
end_date_bound_to_trading_date=True,
before_start_days=300,
keep_before=False,
debug=False,
m_name="""m2"""
)
# @module(position="-327,164", comment="""""", comment_collapsed=True)
m3 = M.bigtrader.v58(
options_data=m2.data,
start_date="""2020-01-01""",
end_date="""2026-03-01""",
initialize=m3_initialize_bigquant_run,
before_trading_start=m3_before_trading_start_bigquant_run,
handle_tick=m3_handle_tick_bigquant_run,
handle_data=m3_handle_data_bigquant_run,
handle_trade=m3_handle_trade_bigquant_run,
handle_order=m3_handle_order_bigquant_run,
after_trading=m3_after_trading_bigquant_run,
capital_base=1000000,
frequency="""daily""",
product_type="""股票""",
rebalance_period_type="""交易日""",
rebalance_period_days="""1""",
rebalance_period_roll_forward=True,
backtest_engine_mode="""标准模式""",
before_start_days=0,
volume_limit=1,
order_price_field_buy="""open""",
order_price_field_sell="""close""",
benchmark="""沪深300指数""",
plot_charts="""全部显示""",
debug=False,
backtest_only=False,
m_name="""m3"""
)
# </aistudiograph>
出现以下错误:\n
[2026-03-18 18:16:24] INFO: dai_sql.v1 开始运行 ..[2026-03-18 18:16:24] INFO: dai_sql.v1 命中缓存[2026-03-18 18:16:24] INFO: dai_sql.v1 运行完成 [0.035s].[2026-03-18 18:16:24] INFO: extract_data_dai.v20 开始运行 ..[2026-03-18 18:16:25] INFO: extract_data_dai.v20 命中缓存[2026-03-18 18:16:25] INFO: extract_data_dai.v20 运行完成 [0.028s].[2026-03-18 18:16:25] INFO: bigtrader.v58 开始运行 ..[2026-03-18 18:16:25] INFO: pybacktest run ~ , , equity, instruments=0
您可以去社区论坛问答交流板块反馈咨询 去发帖>>
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/bigmodule/modulecache.py:106, in get_source(***failed resolving arguments***)
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/bigmodule/modulecache.py:84, in get_source_lines(obj, source_provider)
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/bigmodule/modulecache.py:25, in find_source(obj, loader)
AttributeError: 'NoneType' object has no attribute 'get_source'
During handling of the above exception, another exception occurred:
InvalidInputException Traceback (most recent call last)
Cell In[5], line 153
140 m2 = M.extract_data_dai.v20(
141 sql=m1.data,
142 start_date="""2020-01-01""",
(...)
149 m_name="""m2"""
150 )
152 # @module(position="-327,164", comment="""""", comment_collapsed=True)
--> 153 m3 = M.bigtrader.v58(
154 options_data=m2.data,
155 start_date="""2020-01-01""",
156 end_date="""2026-03-01""",
157 initialize=m3_initialize_bigquant_run,
158 before_trading_start=m3_before_trading_start_bigquant_run,
159 handle_tick=m3_handle_tick_bigquant_run,
160 handle_data=m3_handle_data_bigquant_run,
161 handle_trade=m3_handle_trade_bigquant_run,
162 handle_order=m3_handle_order_bigquant_run,
163 after_trading=m3_after_trading_bigquant_run,
164 capital_base=1000000,
165 frequency="""daily""",
166 product_type="""股票""",
167 rebalance_period_type="""交易日""",
168 rebalance_period_days="""1""",
169 rebalance_period_roll_forward=True,
170 backtest_engine_mode="""标准模式""",
171 before_start_days=0,
172 volume_limit=1,
173 order_price_field_buy="""open""",
174 order_price_field_sell="""close""",
175 benchmark="""沪深300指数""",
176 plot_charts="""全部显示""",
177 debug=False,
178 backtest_only=False,
179 m_name="""m3"""
180 )
181 # </aistudiograph>
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/bigmodule/modules.py:28, in __call__(self, **kwargs)
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/bigmodule/moduleinvoker.py:218, in module_invoke(name, version, kwargs)
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/bigmodule/moduleinvoker.py:181, in _module_invoke(name, version, kwargs)
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/bigmodule/moduleinvoker.py:44, in _module_run(module, kwargs)
File dist/build/bigtrader/v58/__init__.py:444, in v58.run()
File dist/build/bigtrader/v58/__init__.py:222, in v58._run()
File dist/build/bigtrader/v58/__init__.py:208, in v58._run_backtest()
File dist/build/bigtrader/v58/core/pybacktest/__init__.py:176, in v58.core.pybacktest.BigQuantModule.__init__()
File /opt/pyenv/versions/3.11.8/lib/python3.11/site-packages/vectortrader/rebalanceperiod.py:48, in build(self, start_date, end_date, extra_days)
File /var/app/enabled/dai/_telemetry.py:128, in wrapper(*args, **kwargs)
File /var/app/enabled/dai/_functions.py:126, in df(self)
InvalidInputException: Invalid Input Error: Attempting to execute an unsuccessful or closed pending query result
Error: Invalid Input Error: Failed to cast value: Could not convert string '' to INT64
这个我也是搞不明白,哪里需要类型转换而且转换失败了
\
问题三
可视化编辑的使用,以我这个可视化代码为例:
- m2数据抽取的用处是啥,我直接在m1 DAI SQL的SQL中过滤不是最高效的吗?我看到DAI SQL的帮助文档里写的输出端是“data:data,输出(SQL文件)”,这到底是输出了数据本身,还是只是把SQL传给了下游,这两种情况对于m2的处理逻辑就不一样了。
- m2和m3都要填写开始时间和结束时间,重复填写的意义是啥?如果只写m2的,那么m3会自动取m2的吗?
- 节点直接传递数据的方式不明:现在看起来的方式是数据抽取DAI会输出一个data变量,然后在context中直接使用这个变量?
\
问题四
调试功能似乎完全没法用。