策略名称:动量轮动策略
策略说明:
本策略基于动量效应,通过筛选过去一段时间内表现优异的股票进行投资。策略的核心思想是捕捉市场中的趋势,利用股票的短期动量获取超额收益。
策略核心逻辑:
-
股票池筛选:
-
筛选主板和中小板股票,排除科创板、北交所股票。
-
排除上市未满250天的次新股。
-
排除停牌、ST股和退市标签的股票。
-
-
动量计算:
-
计算每只股票过去91天的收益率(动量)。
-
筛选动量最大的10只股票作为投资标的。
-
-
交易决策:
-
每日开盘前,根据动量筛选出目标股票。
-
每日开盘时,卖出不在目标股票列表中的持仓股票,买入新筛选的目标股票。
-
-
风险控制:
-
排除股价低于5元的股票,避免低价股的高波动风险。
-
限制持仓数量为10只,分散投资风险。
-
策略特点:
-
动量效应:通过捕捉股票的短期趋势,获取超额收益。
-
动态调仓:每日根据动量筛选结果调整持仓,保持组合的时效性。
-
风险分散:限制持仓数量,避免过度集中风险。
适用场景:
-
适用于A股市场,能够有效捕捉市场中的短期趋势。
-
适合短线交易者,通过快速交易获取收益。
风险提示:
-
动量策略在震荡市中可能表现不佳,需注意市场风险。
-
策略依赖于历史数据的有效性,需定期优化参数以适应市场变化。
策略代码结构:
-
初始化函数(
initialize):-
设定基准指数(沪深300)。
-
配置交易手续费和滑点。
-
定义每日运行的函数(开盘前、开盘时、收盘后)。
-
-
开盘前运行函数(
before_market_open):-
筛选符合条件的股票,计算动量,更新目标股票列表。
-
-
开盘时运行函数(
market_open):-
根据目标股票列表调整持仓,卖出不在目标列表中的股票,买入新筛选的目标股票。
-
-
动量计算函数(
get_momentum):-
计算每只股票过去91天的收益率,筛选动量最大的10只股票。
-
-
过滤函数:
-
filter_trade_stock:筛选主板和中小板股票。 -
filter_new_stock:排除上市未满250天的次新股。 -
filter_paused_stock:排除停牌股票。 -
filter_st_stock:排除ST股和退市标签的股票。
-
-
复盘函数(
print_trade_info):-
打印每日成交记录和持仓信息,便于复盘分析。
-
策略优化建议:
-
参数优化:
-
可对动量计算周期(如91天)进行优化,以适应不同的市场周期。
-
调整持仓数量(如10只),以平衡风险与收益。
-
-
风险控制:
-
增加最大回撤限制,当回撤超过一定比例时暂停交易。
-
设置单笔交易的最大亏损比例,避免单笔交易亏损过大。
-
-
多因子结合:
-
可结合其他技术指标(如成交量、MACD等)进行综合筛选,提高策略的稳定性。
-
总结:
本策略通过动量效应捕捉市场中的短期趋势,适合短线交易者在A股市场中获取收益。策略逻辑清晰,适合有一定编程基础的投资者进行进一步优化和实盘测试。
策略代码
# 年化62%的动量策略
#导入函数库
from jqdata import *
from jqfactor import get_factor_values
import numpy as np
import pandas as pd
from heapq import nlargest
#初始化函数
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 用真实价格交易
set_option('use_real_price', True)
# 打开防未来函数
set_option("avoid_future_data", True)
# 将滑点设置为0
set_slippage(FixedSlippage(0))
# 设置交易成本万分之三
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, close_today_commission=0, min_commission=5),type='fund')
# 过滤order中低于error级别的日志
log.set_level('order', 'error')
#选股参数
g.stock_num = 10 #持仓数
g.day_count = 91 #动量计算参数
g.stock_price = 5 #股价筛选参数
# 开盘前运行
run_daily(before_market_open, time='before_open', reference_security='000300.XSHG')
# 开盘时运行
run_daily(market_open, time='open', reference_security='000300.XSHG')
run_daily(print_trade_info, time='15:30', reference_security='000300.XSHG')
## 开盘前运行函数
def before_market_open(context):
# 输出运行时间
log.info('函数运行时间(before_market_open):'+str(context.current_dt.time()))
# 要操作的股票:(g.为全局变量)
initial_list = get_all_securities().index.tolist()
initial_list = filter_trade_stock(context, initial_list)
initial_list = filter_new_stock(context,initial_list)
initial_list = filter_paused_stock(initial_list)
initial_list = filter_st_stock(initial_list)
#接下来预持有的代码
next_holding_codes = get_momentum(context, initial_list)
#持有的代码
holding_codes=list(context.portfolio.positions.keys())
#在昨日持仓列表中而不在今日预持仓列表中
g.security1 = [x for x in holding_codes if x not in next_holding_codes]
#在今日预持仓列表中而不在昨日持仓列表中
g.security2 = [y for y in next_holding_codes if y not in holding_codes]
# 给微信发送消息(添加模拟交易,并绑定微信生效)
# send_message('美好的一天~')
## 开盘时运行函数
def market_open(context):
log.info('函数运行时间(market_open):'+str(context.current_dt.time()))
security1 = g.security1
security2 = g.security2
#平仓
for stock in security1:
order_target(stock, 0)
#开仓
cash = context.portfolio.available_cash / len(security2)
for stock in security2:
order_value(stock, cash)
关键函数解锁后查看:
#1 过滤模块-选取主板、中小板
#输入股票列表,返回选取主板、中小板后的列表
def filter_trade_stock(context, stock_list):
return [stock for stock in stock_list if stock[0:2] == '60' or stock[0:2] == '00']
#2 过滤次新股
#输入股票列表,返回剔除上市日期不足250日股票后的列表
def filter_new_stock(context,stock_list):
yesterday = context.previous_date
return [stock for stock in stock_list if not yesterday - get_security_info(stock).start_date < datetime.timedelta(days=250)]
#3 过滤模块-过滤停牌股票
#输入选股列表,返回剔除停牌股票后的列表
def filter_paused_stock(stock_list):
current_data = get_current_data()
return [stock for stock in stock_list if not current_data[stock].paused]
#4 过滤模块-过滤ST及其他具有退市标签的股票
#输入选股列表,返回剔除ST及其他具有退市标签股票后的列表
def filter_st_stock(stock_list):
current_data = get_current_data()
return [stock for stock in stock_list
if not current_data[stock].is_st
and 'ST' not in current_data[stock].name
and '*' not in current_data[stock].name
and '退' not in current_data[stock].name]
#复盘模块-打印
#打印每日持仓信息
def print_trade_info(context):
#打印当天成交记录
trades = get_trades()
for _trade in trades.values():
print('成交记录:'+str(_trade))
#打印账户信息
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('———————————————————————————————————')
print('———————————————————————————————————————分割线————————————————————————————————————————')
2025-02-23
