3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
这是一个基于 QMT 平台的 买入跨式期权(Long Straddle) 策略示例。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
import time
def init(ContextInfo):
"""
策略初始化函数
"""
# ================= 策略参数设置 =================
# 标的资产:这里以 50ETF (510050.SH) 为例
ContextInfo.underlying = '510050.SH'
# 资金账号 (请务必修改为您自己的实盘或模拟账号)
ContextInfo.account_id = 'YOUR_ACCOUNT_ID'
# 交易数量 (手)
ContextInfo.trade_volume = 1
# 策略运行状态标记,防止重复开仓
ContextInfo.has_opened = False
# 设置账号
ContextInfo.set_account(ContextInfo.account_id)
print("策略初始化完成,标的:{}, 账号:{}".format(ContextInfo.underlying, ContextInfo.account_id))
def get_atm_options(ContextInfo, underlying_price):
"""
获取平值(ATM)期权合约对 (Call, Put)
逻辑:
1. 获取当前所有可交易期权
2. 筛选出最近到期月份的合约
3. 找到行权价与当前标的价格差值最小的合约
"""
# 获取当前日期,格式 YYYYMMDD
current_date = time.strftime('%Y%m%d', time.localtime(time.time()))
# 获取标的对应的所有可交易期权合约列表
# isavailable=True 表示获取当前可交易的
option_list = ContextInfo.get_option_list(ContextInfo.underlying, current_date, "", True)
if not option_list:
print("未获取到期权合约列表")
return None, None
# 存储期权信息的列表
options_data = []
for opt_code in option_list:
# 获取合约详细信息
detail = ContextInfo.get_instrumentdetail(opt_code)
# 过滤掉非期权品种或数据异常的
if not detail or 'ExpireDate' not in detail or 'OptExercisePrice' not in detail:
continue
# 简单筛选:只看最近到期的(这里简化逻辑,取列表中的第一个到期日作为目标到期日)
# 实际生产中可能需要更复杂的逻辑来锁定特定月份(如当月或次月)
options_data.append({
'code': opt_code,
'expire_date': detail['ExpireDate'],
'strike_price': detail['OptExercisePrice'],
'type': detail['optType'] # 'CALL' or 'PUT'
})
if not options_data:
return None, None
# 转为 DataFrame 方便处理
df = pd.DataFrame(options_data)
# 1. 筛选最近的到期日 (最小的 ExpireDate)
min_expire = df['expire_date'].min()
df_near = df[df['expire_date'] == min_expire]
# 2. 计算行权价与标的价格的差值的绝对值
df_near['diff'] = abs(df_near['strike_price'] - underlying_price)
# 3. 找到差值最小的行权价 (即平值 ATM)
min_diff = df_near['diff'].min()
target_strike = df_near[df_near['diff'] == min_diff]['strike_price'].iloc[0]
# 4. 获取该行权价下的 Call 和 Put
atm_call = df_near[(df_near['strike_price'] == target_strike) & (df_near['type'] == 'CALL')]['code'].values
atm_put = df_near[(df_near['strike_price'] == target_strike) & (df_near['type'] == 'PUT')]['code'].values
call_code = atm_call[0] if len(atm_call) > 0 else None
put_code = atm_put[0] if len(atm_put) > 0 else None
return call_code, put_code
def handlebar(ContextInfo):
"""
K线周期运行函数
"""
# 必须是实盘或回测的最后一根K线才执行交易逻辑
if not ContextInfo.is_last_bar():
return
# 如果已经开仓,则不再开仓 (示例策略仅演示开仓逻辑)
if ContextInfo.has_opened:
return
# 1. 获取标的最新价格
# get_market_data_ex 返回的是 dict {code: dataframe}
market_data = ContextInfo.get_market_data_ex(
['close'],
[ContextInfo.underlying],
period='1d',
count=1,
subscribe=True
)
if ContextInfo.underlying not in market_data:
print("未获取到标的行情")
return
current_price = market_data[ContextInfo.underlying].iloc[-1]['close']
print("当前标的 {} 价格: {}".format(ContextInfo.underlying, current_price))
# 2. 获取平值期权合约
call_code, put_code = get_atm_options(ContextInfo, current_price)
if not call_code or not put_code:
print("未找到合适的平值期权合约")
return
print("选定平值期权对 -> Call: {}, Put: {}".format(call_code, put_code))
# 3. 下单交易 (买入跨式:买 Call + 买 Put)
# 注意:期权买方通常使用 buy_open (买入开仓)
# 买入认购
print("正在买入认购期权: {}".format(call_code))
buy_open(call_code, ContextInfo.trade_volume, "LATEST", 0, ContextInfo, ContextInfo.account_id)
# 买入认沽
print("正在买入认沽期权: {}".format(put_code))
buy_open(put_code, ContextInfo.trade_volume, "LATEST", 0, ContextInfo, ContextInfo.account_id)
# 标记已开仓
ContextInfo.has_opened = True
print("跨式策略开仓指令已发送")
get_atm_options 函数:
ContextInfo.get_option_list 获取标的关联的所有期权。ContextInfo.get_instrumentdetail 获取期权的详细信息(行权价、到期日、类型)。abs(strike_price - underlying_price) 最小化算法找到最接近当前价格的行权价(即平值期权)。buy_open 交易函数:
buy_open(stockcode, amount, style, price, ContextInfo, accId)"LATEST" (最新价) 进行下单,实盘中为了保证成交,有时会使用对手价 "COMPETE" 或指定价格。防重复开仓:
ContextInfo.has_opened 变量。在实际策略中,您应该通过 get_trade_detail_data 查询实际持仓来判断是否需要开仓,而不是仅靠一个变量。'YOUR_ACCOUNT_ID' 替换为您实际的 QMT 资金账号(期权账号)。510050.SH 及其对应期权合约的历史数据。Q: 如何修改为卖出跨式(做空波动率)?
A: 将 buy_open 改为 sell_open 即可。但请注意,卖出跨式风险无限(理论上),需要缴纳保证金,风险极高。
Q: 如何指定交易特定月份的期权?
A: 在 get_atm_options 函数中,df_near = df[df['expire_date'] == min_expire] 这一行选取了最近的到期日。你可以修改逻辑,比如判断 expire_date 是否包含特定的月份字符串(如 '202312')。
Q: 为什么获取不到期权数据?
A: 请检查 QMT 客户端右下角的连接状态是否正常,以及是否在“数据管理”中补充了期权的基础数据。