from jqdata import * def initialize(context): # 策略初始化设置 set_params(context) # 设置参数 set_backtest() # 设置回测条件 def set_params(context): # 配置策略参数 context.stock_pool = [ {'code': '399673.XSHE', 'name': '创业板50'}, {'code': '000688.XSHG', 'name': '科创50'}, {'code': '399303.XSHE', 'name': '国证2000'} ] context.bond_code = '000012.XSHG' # 国债指数 context.cy_index = '399006.XSHE' # 创业板指 context.ma_days = 20 # 均线周期 context.rank_days = 20 # 排名计算周期 context.sell_ma = 10 # 卖出均线周期 def set_backtest(): # 回测设置 set_benchmark('399673.XSHE') set_option('use_real_price', True) set_order_cost(OrderCost( open_tax=0, close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5 ), type='stock') def handle_data(context, data): # 每日交易逻辑 if not is_trading_day(context): return check_sell_condition(context, data) # 持仓时判断平仓 check_buy_condition(context, data) # 空仓时判断开仓 def is_trading_day(context): # 判断是否为交易日 return not (context.current_dt.hour == 15 and context.current_dt.minute == 0) def check_sell_condition(context, data): # 平仓条件判断 for stock in context.portfolio.positions: if stock.code == context.bond_code: continue current_price = data[stock.code].close ma10 = get_ma(stock.code, context.sell_ma, data) if current_price < ma10: clear_position(context, stock.code) log.info(f"触发平仓条件:{stock.code} 价格跌破10日均线") def check_buy_condition(context, data): # 开仓条件判断 if len(context.portfolio.positions) > 0: return # 大盘择时判断 cy_price = data[context.cy_index].close cy_ma20 = get_ma(context.cy_index, context.ma_days, data) if cy_price <= cy_ma20: return # 计算标的排名 ranked_stocks = [] for stock in context.stock_pool: current_price = data[stock['code']].close ma20 = get_ma(stock['code'], context.rank_days, data) ratio = (current_price - ma20) / ma20 ranked_stocks.append((stock, ratio)) # 按涨幅排序 ranked_stocks.sort(key=lambda x: x[1], reverse=True) target_stock = ranked_stocks[0][0] # 开仓条件验证 current_price = data[target_stock['code']] cy_ma20 = get_ma(context.cy_index, context.ma_days, data) NameError: name 'get_ma' is not defined
时间: 2025-06-10 09:02:45 浏览: 33
<think>好的,我现在需要帮助用户解决他们提供的Python代码中的问题。首先,用户提到有一个NameError: name 'get_ma' is not defined的错误。这说明代码中调用了一个名为get_ma的函数,但这个函数并没有被定义。我需要检查代码,看看哪里调用了get_ma,然后确认是否真的没有定义。
首先,我查看用户提供的代码。在函数check_sell_condition中,有ma10 = get_ma(stock.code, context.sell_ma, data)。同样,在check_buy_condition中,有cy_ma20 = get_ma(context.cy_index, context.ma_days, data)和其他几次调用。显然,代码中多次使用了get_ma函数,但整个代码中并没有这个函数的定义,所以导致NameError。
接下来,我需要确定如何解决这个问题。通常,这样的函数是用来计算移动平均线的,所以需要实现一个计算移动平均的函数。用户可能在代码中遗漏了这个函数的定义。因此,解决方案应该是添加一个get_ma函数,该函数接收股票代码、均线周期和数据,返回对应的移动平均值。
然后,我检查代码的其他部分是否有其他潜在问题。例如,在check_buy_condition中,有一行current_price = data[target_stock['code']] cy_ma20 = ...,这里看起来像是代码换行错误,导致语法错误。正确的写法应该是分两行,或者使用续行符。这可能是一个打字错误,导致IndentationError或其他语法错误。
此外,代码中可能存在其他小问题,比如变量命名、逻辑错误等,但用户当前的主要问题是NameError,所以应优先解决这个。
总结问题:
1. 缺少get_ma函数的定义。
2. 代码中的某行存在语法错误,可能由于换行不当导致。
接下来,我需要编写一个合适的get_ma函数。通常,计算移动平均线需要获取历史数据,然后计算平均值。在聚宽(jqdata)的环境中,可以使用attribute_history函数来获取历史收盘价,然后计算均值。
所以,get_ma函数可能如下:
def get_ma(security, n, data):
# 获取最近n天的收盘价均值
prices = data[security].close
# 或者使用attribute_history获取历史数据
# 这里可能需要根据上下文调整实现
# 例如:hist = attribute_history(security, n, '1d', ['close'])
# return hist['close'].mean()
# 但当前代码中的data可能已经包含足够的信息,需要确认
# 假设data是当前可用的数据,可能需要使用历史数据
# 这里可能需要调整实现方式
但根据聚宽的API,正确的方式可能是使用attribute_history来获取历史数据,因为data参数在handle_data中可能只包含当天的数据。因此,正确的get_ma函数应该获取过去n天的收盘价,计算均值。
因此,正确的实现应该是:
def get_ma(security, n, data=None):
# 获取最近n天的收盘价均值
hist = attribute_history(security, n, '1d', ['close'])
return hist['close'].mean()
但需要考虑是否需要传入data参数,或者是否可以直接使用attribute_history。在用户的代码中,可能data参数在handle_data中被传入,但实际在聚宽环境中,attribute_history是内置函数,可以直接调用,不需要依赖传入的data。因此,可能需要调整函数定义,去掉data参数,或者正确处理。
另外,在用户的代码中,调用get_ma时传入了data参数,所以函数定义需要接受这个参数,即使不使用。或者可能用户希望利用data中的数据,但需要确认。
例如,在check_sell_condition中,data[stock.code].close可能是当天的价格,而计算均线需要过去n天的数据,包括当天。因此,使用attribute_history(n)会包含当天在内的过去n天数据,而如果当天的数据还未完全形成(比如在盘中),可能会有问题。但回测时,handle_data是按天执行的,所以可能没问题。
因此,正确的get_ma函数应该使用attribute_history来获取历史数据。
另外,用户代码中的另一个错误是在check_buy_condition中的这一行:
current_price = data[target_stock['code']] cy_ma20 = get_ma(context.cy_index, context.ma_days, data)
这显然是两行代码被错误地写在同一行,导致语法错误。应该分成两行:
current_price = data[target_stock['code']].close
cy_ma20 = get_ma(context.cy_index, context.ma_days, data)
或者可能是其他打字错误,比如缺少点号或者变量名错误。
此外,在check_buy_condition中,用户可能想获取target_stock的当前价格,然后再次检查cy_ma20的条件?或者这行代码是多余的?需要根据策略逻辑判断。
总结需要修复的地方:
1. 添加get_ma函数的定义。
2. 修复check_buy_condition中的语法错误,将两行代码正确分开。
3. 确保其他逻辑正确,比如在开仓时是否满足条件。
现在,我需要将这些分析整理成用户能够理解的步骤,并给出修正后的代码示例。</think>这是一个基于均线的多指数轮动策略,代码存在以下问题需要修正:
**问题分析及解决方案:**
1. **缺少移动平均函数** ➔ 补充`get_ma`函数定义
2. **语法错误** ➔ 修正`current_price = data[target_stock['code']] cy_ma20 = ...`的错误换行
3. **变量作用域问题** ➔ 在`check_buy_condition`中补充`cy_ma20`重复定义问题
**修正后的完整代码:**
```python
from jqdata import *
def initialize(context):
set_params(context) # 设置参数
set_backtest() # 设置回测条件
def set_params(context):
context.stock_pool = [
{'code': '399673.XSHE', 'name': '创业板50'},
{'code': '000688.XSHG', 'name': '科创50'},
{'code': '399303.XSHE', 'name': '国证2000'}
]
context.bond_code = '000012.XSHG' # 国债指数
context.cy_index = '399006.XSHE' # 创业板指
context.ma_days = 20 # 均线周期
context.rank_days = 20 # 排名计算周期
context.sell_ma = 10 # 卖出均线周期
def set_backtest():
set_benchmark('399673.XSHE')
set_option('use_real_price', True)
set_order_cost(OrderCost(
open_tax=0,
close_tax=0.001,
open_commission=0.0003,
close_commission=0.0003,
min_commission=5
), type='stock')
# 新增移动平均计算函数
def get_ma(security, n_days, data):
"""计算N日移动平均线"""
hist = attribute_history(security, n_days, fields='close')
return hist['close'].mean()
def handle_data(context, data):
if not is_trading_day(context): return
check_sell_condition(context, data)
check_buy_condition(context, data)
def is_trading_day(context):
return not (context.current_dt.hour == 15 and context.current_dt.minute == 0)
def check_sell_condition(context, data):
for stock in context.portfolio.positions:
if stock.code == context.bond_code: continue
current_price = data[stock.code].close
ma10 = get_ma(stock.code, context.sell_ma, data)
if current_price < ma10:
clear_position(context, stock.code)
log.info(f"触发平仓条件:{stock.code} 价格跌破10日均线")
def check_buy_condition(context, data):
if len(context.portfolio.positions) > 0: return
# 大盘择时判断
cy_price = data[context.cy_index].close
cy_ma20 = get_ma(context.cy_index, context.ma_days, data)
if cy_price <= cy_ma20: return
# 计算标的排名
ranked_stocks = []
for stock in context.stock_pool:
current_price = data[stock['code']].close
ma20 = get_ma(stock['code'], context.rank_days, data)
ratio = (current_price - ma20) / ma20
ranked_stocks.append((stock, ratio))
# 按涨幅排序
ranked_stocks.sort(key=lambda x: x[1], reverse=True)
target_stock = ranked_stocks[0][0]
# 修正此行语法错误
current_price = data[target_stock['code']].close # 获取标的当前价格
cy_ma20 = get_ma(context.cy_index, context.ma_days, data) # 重新获取创业板指MA20
# 最终开仓判断
if current_price > cy_ma20:
order_value(target_stock['code'], context.portfolio.available_cash)
log.info(f"开仓买入:{target_stock['name']}")
def clear_position(context, code):
"""清空指定标的持仓"""
order_target(code, 0)
```
**策略逻辑说明:**
1. **择时条件**:
- 当创业板指($399006.XSHE$)价格位于20日均线之上时,认为处于多头市场
- 计算三大指数(创业板50/科创50/国证2000)的`(现价-20日均价)/20日均价`比值
- 选择相对强度最高的指数进行买入
2. **风控机制**:
- 当持仓标的跌破10日均线时平仓
- 每日15:00不进行交易操作
3. **资金管理**:
- 每次开仓使用全部可用资金
- 交易成本包含0.03%佣金(最低5元)和0.1%印花税
该策略通过跟踪宽基指数的相对强度进行轮动,结合大盘趋势择时和均线风控,适合在结构性行情中捕捉强势板块。
阅读全文
相关推荐

















