策略核心思想
策略详细逻辑
1. 股票池筛选
2. 选股因子
3. 动态仓位管理
4. 交易执行
5. 特殊处理
策略特点
风险提示
适用市场环境
参数配置建议
优化方向
from jqdata import *
from jqfactor import *
import numpy as np
import pandas as pd
from datetime import time
from jqdata import finance
from jqdata import get_trade_days
# 初始化函数
def initialize(context):
set_option('avoid_future_data', True)
set_benchmark('399101.XSHE')
set_option('use_real_price', True)
set_slippage(FixedSlippage(6/1000))
set_order_cost(OrderCost(open_tax=0, close_tax=0.001, open_commission=2.5/10000, close_commission=2.5/10000, close_today_commission=0, min_commission=5), type='stock')
log.set_level('order', 'error')
log.set_level('system', 'error')
log.set_level('strategy', 'debug')
g.trading_signal = True
g.run_stoploss = True
g.filter_audit = True
g.adjust_num = True
g.hold_list = []
g.yesterday_HL_list = []
g.target_list = []
g.pass_months = [1, 4]
g.limitup_stocks = []
g.min_mv = 10
g.max_mv = 100
g.stock_num = 5
g.reason_to_sell = {}
g.stoploss_strategy = 3
g.stoploss_limit = 0.09
g.stoploss_market = 0.05
g.highest = 50
g.etf = '511880.XSHG'
g.day_count = 0
g.period = 3
run_daily(prepare_stock_list, '9:05')
run_weekly(weekly_adjustment, 1, '10:30')
run_daily(trade_afternoon, time='14:00', reference_security='399101.XSHE')
run_daily(sell_stocks, time='9:55')
run_daily(close_account, '14:50')
run_daily(check_and_update_cache, '9:00')
g.audit_cache = {}
g.need_to_update_after_labor_day = False
# 准备股票池
def prepare_stock_list(context):
g.hold_list = list(context.portfolio.positions.keys())
g.limitup_stocks = []
if g.hold_list:
df = get_price(g.hold_list, end_date=context.previous_date, frequency='daily', fields=['close', 'high_limit'], count=1, panel=False, fill_paused=False)
g.yesterday_HL_list = df[df['close'] == df['high_limit']]['code'].tolist()
else:
g.yesterday_HL_list = []
g.trading_signal = today_is_between(context)
# 选股模块
def get_stock_list(context):
final_list = []
MKT_index = '399101.XSHE'
ZXBZ_list = get_index_stocks(MKT_index)
initial_list = filter_stocks(context, ZXBZ_list)
q = query(valuation.code).filter(
valuation.code.in_(initial_list),
indicator.roe > 0.15,
indicator.roa > 0.10
).order_by(valuation.market_cap.asc()).limit(g.stock_num * 3)
df = get_fundamentals(q)
if g.filter_audit:
all_codes = df['code'].tolist()
audit_results = {code: filter_audit(context, code) for code in all_codes}
df['audit'] = df['code'].map(audit_results)
df = df[df['audit']]
log.info('去除掉了存在审计问题的股票{}只'.format(len(df[~df['audit']]) if not df.empty else 0))
if not df.empty:
final_list = df['code'].tolist()
last_prices = history(1, unit='1d', field='close', security_list=final_list)
final_list = [stock for stock in final_list if stock in g.hold_list or (last_prices[stock][-1] <= g.highest if stock in last_prices else True)]
if not final_list:
log.info('无适合股票,买入ETF')
return [g.etf]
else:
return final_list
# 整体调整持仓
def weekly_adjustment(context):
if g.trading_signal:
g.day_count = 0
if g.adjust_num:
new_num = adjust_stock_num(context)
g.stock_num = new_num
log.info(f'持仓数量修改为{new_num}')
g.target_list = get_stock_list(context)[:g.stock_num]
log.info(str(g.target_list))
sell_list = [stock for stock in g.hold_list if stock not in g.target_list and stock not in g.yesterday_HL_list]
hold_list = [stock for stock in g.hold_list if stock in g.target_list or stock in g.yesterday_HL_list]
log.info("卖出[%s]" % (str(sell_list)))
log.info("已持有[%s]" % (str(hold_list)))
for stock in sell_list:
order_target_value(stock, 0)
for stock in hold_list:
indiv_value = context.portfolio.total_value / g.stock_num
order_target_value(stock, indiv_value)
buy_list = [stock for stock in g.target_list if stock not in g.hold_list]
buy_security(context, buy_list, len(buy_list))
else:
buy_security(context, [g.etf], 1)
log.info('该月份为空仓月份,持有银华日利ETF')
关键函数解锁后查看:
# 交易模块-自定义下单
def order_target_value_(security, value):
try:
if value == 0:
pass
else:
log.debug("Order %s to value %f" % (security, value))
return order_target_value(security, value)
except Exception as e:
log.error(f"下单 {security} 至价值 {value} 时出错: {e}")
return None
# 交易模块-开仓
def open_position(security, value):
try:
order = order_target_value_(security, value)
if order is not None and order.filled > 0:
return True
return False
except Exception as e:
log.error(f"开仓 {security} 价值为 {value} 时出错: {e}")
return False
# 交易模块-平仓
def close_position(position):
security = position.security
try:
order = order_target_value_(security, 0)
if order is not None:
if order.status == OrderStatus.held and order.filled == order.amount:
return True
return False
except Exception as e:
log.error(f"平仓 {security} 时出错: {e}")
return False
# 买入模块
def buy_security(context, target_list, num):
position_count = len(context.portfolio.positions)
target_num = num
if target_num != 0:
value = context.portfolio.total_value / target_num
for stock in target_list:
open_position(stock, value)
log.info("买入[%s](%s元)" % (stock, value))
if len(context.portfolio.positions) == g.stock_num:
break
# 判断今天是否跳过月份
def today_is_between(context):
month = context.current_dt.month
return False if month in g.pass_months else True
# 清仓后次日资金可转
def close_account(context):
if not g.trading_signal:
if g.hold_list and g.hold_list != [g.etf]:
for stock in g.hold_list:
position = context.portfolio.positions[stock]
close_position(position)
log.info("卖出[%s]" % (stock))
# 打印持仓信息
def print_position_info(context):
for position in list(context.portfolio.positions.values()):
securities = position.security
cost = position.avg_cost
price = position.price
ret = 100 * (price / cost - 1)
value = position.value
amount = position.total_amount
print('代码:{}'.format(securities))
print('成本价:{}'.format(format(cost, '.2f')))
print('现价:{}'.format(price))
print('收益率:{}%'.format(format(ret, '.2f')))
print('持仓(股):{}'.format(amount))
print('市值:{}'.format(format(value, '.2f')))
print('———————————————————————————————————————分割线————————————————————————————————————————')
# 检查剩余金额并买入
def check_remain_amount(context):
stoploss_list = []
uplimit_list = []
for key, value in g.reason_to_sell.items():
if value == 'stoploss':
stoploss_list.append(key)
elif value == 'limitup':
uplimit_list.append(key)
empty_num = len(stoploss_list) + len(uplimit_list)
addstock_num = len(uplimit_list)
etf_num = len(stoploss_list)
g.hold_list = list(context.portfolio.positions.keys())
if len(g.hold_list) < g.stock_num:
num_stocks_to_buy = min(addstock_num, g.stock_num - len(g.hold_list))
target_list = [stock for stock in g.target_list if stock not in g.limitup_stocks][:num_stocks_to_buy]
log.info('有余额可用' + str(round(context.portfolio.cash, 2)) + '元。买入' + str(target_list))
buy_security(context, target_list, len(target_list))
if etf_num != 0:
log.info('有余额可用' + str(round(context.portfolio.cash, 2)) + '元。买入货币基金' + str(g.etf))
buy_security(context, [g.etf], etf_num)
g.reason_to_sell = {}
2025-03-28
