Warning: file_exists(): open_basedir restriction in effect. File(/www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/wp-content/db.php) is not within the allowed path(s): (/www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/:/tmp/:/proc/:/var/log/nginx/:/www/wwwroot/com.xiximiao.oa/com.cmstop/public/:/www/wwwroot/com.xiximiao.oa/com.cmstop/vendor/:/www/wwwroot/com.xiximiao.oa/com.cmstop/ppk/) in /www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/wp-includes/load.php on line 707
2354 行业轮动强势股追涨策略 追市场热点策略 42186 量化策略 自动化交易实现代码 » 轻知量化 QMT、PTrade、聚宽策略分享交流平台

2354 行业轮动强势股追涨策略 追市场热点策略 42186 量化策略 自动化交易实现代码

行业轮动强势股追涨策略


策略逻辑说明:

1. 策略核心思想

该策略基于行业轮动强势股追涨的逻辑,通过筛选出近期表现强势的行业和个股,结合技术指标(如DMI)进行买入和卖出操作。策略的核心思想是:

  • 行业轮动:通过申万行业分类,筛选出近期表现较好的行业,从中选择强势股票。

  • 强势股追涨:通过技术指标(如DMI)筛选出短期内有上涨动能的股票,并在合适的时机买入。

  • 动态调仓:根据市场情况动态调整持仓,及时卖出表现不佳的股票,锁定盈利。


2. 策略运行流程

策略的运行流程分为以下几个步骤:

2.1 每周准备股票池
  • 行业评分:通过申万行业分类,计算每个行业的涨跌得分,筛选出近期表现较好的行业。

  • 股票筛选:从表现较好的行业中,筛选出符合条件的股票(如非ST股、非停牌股、非次新股等)。

  • 强势股筛选:通过DMI指标筛选出短期内有上涨动能的股票,形成候选股票池。

2.2 每日准备股票列表
  • 持仓监控:获取当前持仓的股票列表,并记录昨日涨停的股票。

  • 买入列表生成:根据候选股票池,筛选出今日可以买入的股票,分为早上买入和中午买入两个列表。

    • 早上买入:开盘价低于昨日收盘价一定比例的股票。

    • 中午买入:当前价格高于昨日收盘价一定比例且未涨停的股票。

2.3 买入操作
  • 早上买入:在开盘后不久,买入早上买入列表中的股票。

  • 中午买入:在中午开盘后不久,买入中午买入列表中的股票。

  • 资金分配:根据可用资金和持仓数量,平均分配资金买入股票。

2.4 卖出操作
  • 跌幅过大卖出:如果持仓中的股票跌幅超过一定比例(如2%),则卖出。

  • 涨停打开卖出:如果昨日涨停的股票今日涨停打开,则卖出。

2.5 收盘后操作
  • 成交记录:记录当天的成交记录,并输出日志。


3. 策略特点

  • 行业轮动:通过行业评分筛选出近期表现较好的行业,抓住行业轮动的机会。

  • 强势股追涨:通过DMI指标筛选出短期内有上涨动能的股票,追涨买入。

  • 动态调仓:根据市场情况动态调整持仓,及时卖出表现不佳的股票,锁定盈利。

  • 风险控制:通过过滤ST股、停牌股、次新股等,降低投资风险。


4. 策略适用场景

  • 市场环境:适合震荡市或上涨市,能够抓住行业轮动和个股上涨的机会。

  • 投资者类型:适合有一定量化交易经验的投资者,能够理解策略的逻辑并进行参数调整。


5. 策略优化方向

  • 参数优化:可以调整行业评分的计算方式、DMI指标的参数等,以适应不同的市场环境。

  • 风险控制:可以增加更多的风险控制措施,如止损、止盈等。

  • 多因子筛选:可以引入更多的技术指标或基本面因子,进一步提高选股的准确性。


策略名称解释:

  • 行业轮动:策略通过行业评分筛选出近期表现较好的行业,抓住行业轮动的机会。

  • 强势股追涨:策略通过DMI指标筛选出短期内有上涨动能的股票,追涨买入。

  • 动态调仓:策略根据市场情况动态调整持仓,及时卖出表现不佳的股票,锁定盈利。

行业轮动强势股追涨策略代码

# 导入函数库
from jqdata import *
from jqlib.technical_analysis import *
import pandas as pd

# 初始化函数,设定基准等等
def initialize(context):
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 打开防未来函数
    set_option("avoid_future_data", True)
    # 输出内容到日志 log.info()
    log.info('初始函数开始运行且全局只运行一次')
    # 过滤掉order系列API产生的比error级别低的log
    #log.set_level('order', 'error')

    g.stock_num = 3
    g.hold_list = [] #当前持仓的全部股票    
    g.yesterday_HL_list = [] #记录持仓中昨日涨停的股票
    g.candidate_list = []
    g.buy1_stock_lists = []
    g.buy2_stock_lists = []
    
    ### 股票相关设定 ###
    # 股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')

    ## 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的)
    run_weekly(weekly_prepare_stock, 1, time='7:00', reference_security='000300.XSHG')

    # 开盘时刻准备
    run_daily(prepare_stock_list, time='9:30', reference_security='000300.XSHG')
    # 开盘时刻卖出下跌股票
    run_daily(my_trade_sell, time='9:30', reference_security='000300.XSHG')
    # 中午卖出下跌股票
    run_daily(my_trade_sell, time='13:30', reference_security='000300.XSHG')
    # 中午卖出前一天未涨停
    run_daily(check_limit_up, time='13:30', reference_security='000300.XSHG')
    # 早上买入股票
    run_daily(my_trade_buy1, time='9:31', reference_security='000300.XSHG')
    # 中午买入股票
    run_daily(my_trade_buy2, time='13:31', reference_security='000300.XSHG')
    # 收盘后运行
    run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')


#1-1 准备股票池,每周更换一次
def weekly_prepare_stock(context):
    candidate_list = []
    yes_day = context.previous_date
    #通过申万的股票分类
    df = get_industries(name='sw_l2', date=yes_day)
    #df = get_concepts()
    df['score'] = -100000
    df['nums'] = 0
    drop_index = []
    for industry_index in df.index:
        check_out_lists = get_industry_stocks(industry_index, yes_day)
        df.loc[industry_index, 'nums'] = len(check_out_lists)
        if(len(check_out_lists)>=20):
            score = stock_sector_score(check_out_lists,10)
            df.loc[industry_index, 'score'] = score
        else:
            drop_index.append(industry_index)
    df = df.drop(drop_index)
    df = df.sort_values(by=['score'], ascending=False) #分数越高即预测未来收益越高,排序默认降序
    industry_indexs = df.index[0:5]
    for industry_index in industry_indexs:
        #log.info("%s : %s : 等分%0d : 数量%0d"%(industry_index, df.loc[industry_index, 'name'],
        #        df.loc[industry_index, 'score'], df.loc[industry_index, 'nums']))
        if(df.loc[industry_index, 'score']>500):
            check_out_lists = get_industry_stocks(industry_index, yes_day)
            candidate_list.extend(check_out_lists)
    candidate_list = list(set(candidate_list))
    candidate_list = filter_new_stock(context, candidate_list)
    candidate_list = filter_kcbj_stock(candidate_list)
    candidate_list = filter_st_stock(candidate_list)
    candidate_list = filter_paused_stock(candidate_list)
    candidate_list = find_strong_stock(context, candidate_list)
    candidate_num  = min(g.stock_num+10, len(candidate_list))
    g.candidate_list = candidate_list[:candidate_num]
    log.info("一周准备的股票LIST %0d,如下:"%(candidate_num))
    log.info(g.candidate_list)

关键函数解锁后查看:

##1-3 中午买入股票函数
def my_trade_buy2(context):
    # 根据股票数量分仓
    # 此处只根据可用金额平均分配购买,不能保证每个仓位平均分配
    current_data = get_current_data()
    buy_stocks = g.buy2_stock_lists[:]
    position_count = len(context.portfolio.positions)
    if g.stock_num > position_count:
        value = context.portfolio.cash / (g.stock_num - position_count)
        for stock in buy_stocks:
            dt = attribute_history(stock, 1,'1d',['close'])
            log.info("%s close=%0f, last_price=%0f, high_limit=%0f"%(stock,\
                    dt.close[-1], current_data[stock].last_price, current_data[stock].high_limit))
            if current_data[stock].last_price>dt.close[-1]*1.01 and\
               current_data[stock].last_price<current_data[stock].high_limit and\
               context.portfolio.positions[stock].total_amount == 0:
                if open_position(stock, value):
                    if len(context.portfolio.positions) == g.stock_num:
                        break

#1-4 调整昨日涨停股票
def check_limit_up(context):
    now_time = context.current_dt
    if g.yesterday_HL_list != []:
        #对昨日涨停股票观察到尾盘如不涨停则提前卖出,如果涨停即使不在应买入列表仍暂时持有
        for stock in g.yesterday_HL_list:
            current_data = get_price(stock, end_date=now_time, frequency='1m',\
                           fields=['close','high_limit'], skip_paused=False, fq='pre',\
                           count=1, panel=False, fill_paused=True)
            if current_data.iloc[0,0] <    current_data.iloc[0,1]:
                send_message("[%s]涨停打开,卖出" % (stock))
                log.info("[%s]涨停打开,卖出" % (stock))
                position = context.portfolio.positions[stock]
                close_position(position)
            else:
                send_message("[%s]涨停,继续持有" % (stock))
                log.info("[%s]涨停,继续持有" % (stock))


# 1-5 卖掉跌幅过大的股票
def my_trade_sell(context):
    sell_str  = ''
    sell_stocks = []
    current_data = get_current_data()
    holding_list = list(context.portfolio.positions)
    if holding_list:
        for stock in holding_list:
            dt = attribute_history(stock, 1,'1d',['close'])
            if (current_data[stock].last_price <= dt.close[-1]*0.98): sell_str += '%s '%stock sell_stocks.append(stock) if(len(sell_stocks)>0):
            send_message("[%s]跌幅过大,卖出" % sell_str)
            log.info("[%s]跌幅过大,卖出" % sell_str)
            for stock in sell_stocks:
                position = context.portfolio.positions[stock]
                close_position(position)
                
                
                    
##1-6 收盘后运行函数
def after_market_close(context):
    log.info(str('函数运行时间(after_market_close):'+str(context.current_dt.time())))
    #得到当天所有成交记录
    trades = get_trades()
    for _trade in trades.values():
        log.info('成交记录:'+str(_trade))
    log.info('一天结束')
    log.info('##############################################################')

# 自定义下单
# 根据Joinquant文档,当前报单函数都是阻塞执行,报单函数(如order_target_value)返回即表示报单完成
# 报单成功返回报单(不代表一定会成交),否则返回None
def order_target_value_(security, value):
    if value == 0:
        log.debug("Selling out %s" % (security))
    else:
        log.debug("Order %s to value %f" % (security, value))
    
    # 如果股票停牌,创建报单会失败,order_target_value 返回None
    # 如果股票涨跌停,创建报单会成功,order_target_value 返回Order,但是报单会取消
    # 部成部撤的报单,聚宽状态是已撤,此时成交量>0,可通过成交量判断是否有成交
    return order_target_value(security, value)


# 开仓,买入指定价值的证券
# 报单成功并成交(包括全部成交或部分成交,此时成交量大于0),返回True
# 报单失败或者报单成功但被取消(此时成交量等于0),返回False
def open_position(security, value):
    order = order_target_value_(security, value)
    if order != None and order.filled > 0:
        return True
    return False


# 平仓,卖出指定持仓
# 平仓成功并全部成交,返回True
# 报单失败或者报单成功但被取消(此时成交量等于0),或者报单非全部成交,返回False
def close_position(position):
    security = position.security
    order = order_target_value_(security, 0)  # 可能会因停牌失败
    if order != None:
        if order.status == OrderStatus.held and order.filled == order.amount:
            return True
    return False

#2-1 过滤停牌股票
def filter_paused_stock(stock_list):
    current_data = get_current_data()
    return [stock for stock in stock_list if not current_data[stock].paused]

#2-2 过滤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 current_data[stock].last_price < 40
            and 'ST' not in current_data[stock].name
            and '*' not in current_data[stock].name
            and '退' not in current_data[stock].name]

#2-3 过滤科创北交股票
def filter_kcbj_stock(stock_list):
    for stock in stock_list[:]:
        if stock[0] == '4' or stock[0] == '8' or stock[:2] == '68' or stock[:2] == '30':
            stock_list.remove(stock)
    return stock_list

#2-4 过滤涨停的股票
def filter_limitup_stock(context, stock_list):
    #last_prices = history(1, unit='1m', field='close', security_list=stock_list)
    current_data = get_current_data()
    return [stock for stock in stock_list if stock in context.portfolio.positions.keys()
            or current_data[stock].last_price  < current_data[stock].high_limit] #2-5 过滤跌停的股票 def filter_limitdown_stock(context, stock_list): #last_prices = history(1, unit='1m', field='close', security_list=stock_list) current_data = get_current_data() return [stock for stock in stock_list if stock in context.portfolio.positions.keys() or current_data[stock].last_price > current_data[stock].low_limit]

#2-6 过滤次新股
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=375)] ## 计算N天的板块涨跌得分 def stock_sector_score(stock_list, days): stk_close = history(days, unit='1d', field='close', security_list=stock_list, df=True) stk_preclose = history(days, unit='1d', field='pre_close', security_list=stock_list, df=True) stk_ratio = ((stk_close/stk_preclose)-1)*100 stk_range = pd.IntervalIndex.from_tuples([(-50,-9),(-9,-6),(-6,-3),(-3,0),(0,3),(3,6),(6,9),(9,30)]) stk_counts = pd.cut(stk_ratio[stock_list[0]], bins=stk_range).value_counts(sort=False) for stock in stock_list[1:]: stk_counts = stk_counts+pd.cut(stk_ratio[stock], bins=stk_range).value_counts(sort=False) score = stk_counts[-10]*-1000+stk_counts[-7]*-700+stk_counts[-4]*-400+\ stk_counts[-1]*-100+stk_counts[2]*100+stk_counts[5]*400+\ stk_counts[8]*700+stk_counts[11]*1000 score = score/len(stock_list) return(score) # 选择强势股, 待选股票LIST def find_strong_stock(context, stock_list): strong_stk_dict = {} yesterday = context.previous_date dmi_pdi,dmi_mdi,dmi_adx,dmi_adxr = DMI(stock_list, check_date=yesterday, N= 14, MM = 6, unit='1d', include_now=True) for stock in stock_list: if(dmi_pdi[stock]>dmi_mdi[stock]):
            strong_stk_dict[stock] = dmi_pdi[stock] - dmi_mdi[stock] + dmi_adx[stock]
    #分数从大到小排列
    return_stk = [y[0] for y in sorted(strong_stk_dict.items(), key=lambda x:x[1], reverse=True)]
    return(return_stk)
    
    

2025-02-23
⚠️
本站资源大多来自网络,仅供网友学习交流,未经作者或上传书面授权,请勿作他用。
站长 vx: xiangyin615 或者 留言反馈 ,我们将尽快处理。
Notice: When you of the legal rights be violate, please stir to vx: xiangyin615
个人中心
购物车
优惠劵
搜索