• 10-18


      花了一天时间,根据昨天偷研究的神人账户交割单写的策略,不断调整了参数,回测测试效果惊人的可怕,从07年开始到现在年化140%.

      程序回测结果:

     可以说是相当恐怖了,庆幸自己可以查到如此有价值的数据,感谢FIS。

     测试代码:

    '''
    配置指定频率的调仓日,在调仓日每日指定时间,计算沪深300指数和中证500指数当前的20日涨
    幅,如果2个指数的20日涨幅有一个为正,则进行选股调仓,之后如此循环往复。
    
    止损策略:
    
        大盘止损:
            1. 每分钟取大盘前130日的最低价和最高价,如果最高大于最低的两倍则清仓,停止交易。
            2. 每分钟判断大盘是否呈现三只黑鸦止损,如果是则当天清仓并停止交易,第二天停止交
               易一天。
    
        个股止损:
            每分钟判断个股是否从持仓后的最高价回撤幅度,如果超过个股回撤阈值,则平掉该股持仓
    
        二八止损:
            每日指定时间,计算沪深300指数和中证500指数当前的20日涨幅,如果2个指数涨幅都为负,
            则清仓,重置调仓计数,待下次调仓条件满足再操作
    
    '''
    
    import tradestat
    #from blacklist import *
    
    # blacklist.py
    # 修改黑名单
    
    # 配置股票黑名单
    # 列出当且极不适宜购买的股票
    # 注:1. 黑名单有时效性,回测的时候最好不使用,模拟交易建议使用
    #     2. 用一模块或者大数据分析收集这类股票,定时更新
    def get_blacklist():
    
        blacklist = ["600656.XSHG","300372.XSHE","600403.XSHG","600421.XSHG","600733.XSHG","300399.XSHE",
                     "600145.XSHG","002679.XSHE","000020.XSHE","002330.XSHE","300117.XSHE","300135.XSHE",
                     "002566.XSHE","002119.XSHE","300208.XSHE","002237.XSHE","002608.XSHE","000691.XSHE",
                     "002694.XSHE","002715.XSHE","002211.XSHE","000788.XSHE","300380.XSHE","300028.XSHE",
                     "000668.XSHE","300033.XSHE","300126.XSHE","300340.XSHE","300344.XSHE","002473.XSHE"]
        return blacklist
    
    def before_trading_start(context):
        log.info("---------------------------------------------")
        #log.info("==> before trading start @ %s", str(context.current_dt))
    
        # 盘前就判断三黑鸦状态,因为判断的数据为前4日
        g.is_last_day_3_black_crows = is_3_black_crows(g.index_4_stop_loss_by_3_black_crows)
        if g.is_last_day_3_black_crows:
            log.info("==> 前4日已经构成三黑鸦形态")
        pass
    
    def after_trading_end(context):
        #log.info("==> after trading end @ %s", str(context.current_dt))
        g.trade_stat.report(context)
    
        reset_day_param()
        
        # 得到当前未完成订单
        orders = get_open_orders()
        for _order in orders.values():
            log.info("canceled uncompleted order: %s" %(_order.order_id))
        pass
    
    def initialize(context):
        log.info("==> initialize @ %s", str(context.current_dt))
        
        # 设置手续费率
        set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
        # 设置基准指数:沪深300指数 '000300.XSHG'
        set_benchmark('000300.XSHG')
        # 设定滑点为百分比
        # 没有调用set_slippage函数, 系统默认的滑点是PriceRelatedSlippage(0.00246)
        #set_slippage(PriceRelatedSlippage(0.004))
        # 使用真实价格回测(模拟盘推荐如此,回测请注释)
        set_option('use_real_price', True)
    
        # 加载统计模块
        g.trade_stat = tradestat.trade_stat()
    
        # 配置策略参数
        # 此配置主要为之前的小市值策略,保证之前的收益回撤
        # 如果想要更改,最好新建个函数,调整参数测试其他策略
        # 10日调仓
        # 关闭大盘三乌鸦及高低价止损
        # 关闭个股止盈止损
        # 关闭选股评分
        set_param()
    
        # 缓存股票持仓后的最高价
        g.last_high = {}
    
        # 如下参数不能更改
        if g.is_market_stop_loss_by_price:
            # 记录当日是否满足大盘价格止损条件,每日盘后重置
            g.is_day_stop_loss_by_price = False
    
        # 缓存三黑鸦判断状态
        g.is_last_day_3_black_crows = False
        if g.is_market_stop_loss_by_3_black_crows:
            g.cur_drop_minute_count = 0
    
        if g.is_rank_stock:
            if g.rank_stock_count > g.pick_stock_count:
                g.rank_stock_count = g.pick_stock_count
    
        if g.is_stock_stop_loss or g.is_stock_stop_profit:
            # 缓存当日个股250天内最大的3日涨幅,避免当日反复获取,每日盘后清空
            g.pct_change = {}
    
        # 打印策略参数
        log_param()
    
    def set_param():
        # 调仓频率,单位:日
        g.period = 3
        # 调仓日计数器,单位:日
        g.day_count = 0
        # 配置调仓时间(24小时分钟制)
        g.adjust_position_hour = 14
        g.adjust_position_minute = 50
    
        # 配置选股参数
    
        # 备选股票数目
        g.pick_stock_count = 100
        
        # 配置选股参数
        # 是否根据PE选股
        g.pick_by_pe = False
        # 如果根据PE选股,则配置最大和最小PE值
        if g.pick_by_pe:
            g.max_pe = 200
            g.min_pe = 0
    
        # 是否根据EPS选股
        g.pick_by_eps = True
        # 配置选股最小EPS值
        if g.pick_by_eps:
            g.min_eps = 0
        
        # 配置是否过滤创业板股票
        g.filter_gem = True
        # 配置是否过滤黑名单股票,回测建议关闭,模拟运行时开启
        g.filter_blacklist = True
    
        # 是否对股票评分
        g.is_rank_stock = True
        if g.is_rank_stock:
            # 参与评分的股票数目
            g.rank_stock_count = 20
    
        # 买入股票数目
        g.buy_stock_count = 2
        
        # 配置二八指数
        #g.index2 = '000300.XSHG'  # 沪深300指数,表示二,大盘股
        #g.index8 = '000905.XSHG'  # 中证500指数,表示八,小盘股
        g.index2 = '000016.XSHG'  # 上证50指数
        g.index8 = '399333.XSHE'  # 中小板R指数
        #g.index8 = '399006.XSHE'  # 创业板指数
        
        # 判定调仓的二八指数20日增幅
        #g.index_growth_rate_20 = 0.00
        g.index_growth_rate_20 = 0.01
    
        # 配置是否根据大盘历史价格止损
        # 大盘指数前130日内最高价超过最低价2倍,则清仓止损
        # 注:关闭此止损,收益增加,但回撤会增加
        g.is_market_stop_loss_by_price = True
        if g.is_market_stop_loss_by_price:
            # 配置价格止损判定指数,默认为上证指数,可修改为其他指数
            g.index_4_stop_loss_by_price = '000001.XSHG'
    
        # 配置三黑鸦判定指数,默认为上证指数,可修改为其他指数
        g.index_4_stop_loss_by_3_black_crows = '000001.XSHG'
    
        # 配置是否开启大盘三黑鸦止损
        # 个人认为针对大盘判断三黑鸦效果并不好,首先有效三只乌鸦难以判断,准确率实际来看也不好,
        # 其次,分析历史行情看一般大盘出现三只乌鸦的时候,已经严重滞后了,使用其他止损方式可能会更好
        g.is_market_stop_loss_by_3_black_crows = False
        if g.is_market_stop_loss_by_3_black_crows:
            g.dst_drop_minute_count = 10
    
        # 配置是否个股止损
        g.is_stock_stop_loss =False
        # 配置是否个股止盈
        g.is_stock_stop_profit = False
        
    def log_param():
        log.info("调仓日频率: %d日" %(g.period))
        log.info("调仓时间: %s:%s" %(g.adjust_position_hour, g.adjust_position_minute))
    
        log.info("备选股票数目: %d" %(g.pick_stock_count))
    
        log.info("是否根据PE选股: %s" %(g.pick_by_pe))
        if g.pick_by_pe:
            log.info("选股最大PE: %s" %(g.max_pe))
            log.info("选股最小PE: %s" %(g.min_pe))
    
        log.info("是否根据EPS选股: %s" %(g.pick_by_eps))
        if g.pick_by_eps:
            log.info("选股最小EPS: %s" %(g.min_eps))
        
        log.info("是否过滤创业板股票: %s" %(g.filter_gem))
        log.info("是否过滤黑名单股票: %s" %(g.filter_blacklist))
        if g.filter_blacklist:
            log.info("当前股票黑名单:%s" %str(get_blacklist()))
    
        log.info("是否对股票评分选股: %s" %(g.is_rank_stock))
        if g.is_rank_stock:
            log.info("评分备选股票数目: %d" %(g.rank_stock_count))
    
        log.info("买入股票数目: %d" %(g.buy_stock_count))
    
        log.info("二八指数之二: %s - %s" %(g.index2, get_security_info(g.index2).display_name))
        log.info("二八指数之八: %s - %s" %(g.index8, get_security_info(g.index8).display_name))
        log.info("判定调仓的二八指数20日增幅: %.1f%%" %(g.index_growth_rate_20*100))
    
        log.info("是否开启大盘历史高低价格止损: %s" %(g.is_market_stop_loss_by_price))
        if g.is_market_stop_loss_by_price:
            log.info("大盘价格止损判定指数: %s - %s" %(g.index_4_stop_loss_by_price, get_security_info(g.index_4_stop_loss_by_price).display_name))
    
        log.info("大盘三黑鸦止损判定指数: %s - %s" %(g.index_4_stop_loss_by_3_black_crows, get_security_info(g.index_4_stop_loss_by_3_black_crows).display_name))
        log.info("是否开启大盘三黑鸦止损: %s" %(g.is_market_stop_loss_by_3_black_crows))
        if g.is_market_stop_loss_by_3_black_crows:
            log.info("三黑鸦止损开启需要当日大盘为跌的分钟计数达到: %d" %(g.dst_drop_minute_count))
    
        log.info("是否开启个股止损: %s" %(g.is_stock_stop_loss))
        log.info("是否开启个股止盈: %s" %(g.is_stock_stop_profit))
    
    # 重置当日参数,仅针对需要当日需要重置的参数
    def reset_day_param():
        if g.is_market_stop_loss_by_price:
            # 重置当日大盘价格止损状态
            g.is_day_stop_loss_by_price = False
    
        if g.is_stock_stop_loss or g.is_stock_stop_profit:
            # 清空当日个股250天内最大的3日涨幅的缓存
            g.pct_change.clear()
    
        # 重置三黑鸦状态
        g.is_last_day_3_black_crows = False
        if g.is_market_stop_loss_by_3_black_crows:
            g.cur_drop_minute_count = 0
    
    # 按分钟回测
    def handle_data(context, data):
        if g.is_market_stop_loss_by_price:
            if market_stop_loss_by_price(context, g.index_4_stop_loss_by_price):
                return
    
        if g.is_market_stop_loss_by_3_black_crows:
            if market_stop_loss_by_3_black_crows(context, g.index_4_stop_loss_by_3_black_crows, g.dst_drop_minute_count):
                return
    
        if g.is_stock_stop_loss:
            stock_stop_loss(context, data)
    
        if g.is_stock_stop_profit:
            stock_stop_profit(context, data)
    
        # 获得当前时间
        hour = context.current_dt.hour
        minute = context.current_dt.minute
        
        # 每天下午14:50调仓
        if hour == g.adjust_position_hour and minute == g.adjust_position_minute:
            do_handle_data(context, data)
    
    def do_handle_data(context, data):
        log.info("调仓日计数 [%d]" %(g.day_count))
        
        # 回看指数前20天的涨幅
        gr_index2 = get_growth_rate(g.index2)
        gr_index8 = get_growth_rate(g.index8)
        log.info("当前%s指数的20日涨幅 [%.2f%%]" %(get_security_info(g.index2).display_name, gr_index2*100))
        log.info("当前%s指数的20日涨幅 [%.2f%%]" %(get_security_info(g.index8).display_name, gr_index8*100))
    
        if gr_index2 <= g.index_growth_rate_20 and gr_index8 <= g.index_growth_rate_20:
            clear_position(context)
            g.day_count = 0
        else: #if  gr_index2 > g.index_growth_rate_20 or ret_index8 > g.index_growth_rate_20:
            if g.day_count % g.period == 0:
                log.info("==> 满足条件进行调仓")
                buy_stocks = pick_stocks(context, data)
                log.info("选股后可买股票: %s" %(buy_stocks))
                adjust_position(context, buy_stocks)
            g.day_count += 1
    
    def market_stop_loss_by_price(context, index):
        # 大盘指数前130日内最高价超过最低价2倍,则清仓止损
        # 基于历史数据判定,因此若状态满足,则当天都不会变化
        # 增加此止损,回撤降低,收益降低
    
        if not g.is_day_stop_loss_by_price:
            h = attribute_history(index, 160, unit='1d', fields=('close', 'high', 'low'), skip_paused=True)
            low_price_130 = h.low.min()
            high_price_130 = h.high.max()
            if high_price_130 > 2.2 * low_price_130 and h['close'][-1]<h['close'][-4]*1 and  h['close'][-1]> h['close'][-100]:
                # 当日第一次输出日志
                log.info("==> 大盘止损,%s指数前130日内最高价超过最低价2倍, 最高价: %f, 最低价: %f" %(get_security_info(index).display_name, high_price_130, low_price_130))
                g.is_day_stop_loss_by_price = True
    
        if g.is_day_stop_loss_by_price:
            clear_position(context)
            g.day_count = 0
    
        return g.is_day_stop_loss_by_price
    
    def market_stop_loss_by_3_black_crows(context, index, n):
        # 前日三黑鸦,累计当日每分钟涨幅<0的分钟计数
        # 如果分钟计数超过一定值,则开始进行三黑鸦止损
        # 避免无效三黑鸦乱止损
        if g.is_last_day_3_black_crows:
            if get_growth_rate(index, 1) < 0:
                g.cur_drop_minute_count += 1
    
            if g.cur_drop_minute_count >= n:
                if g.cur_drop_minute_count == n:
                    log.info("==> 超过三黑鸦止损开始")
    
                clear_position(context)
                g.day_count = 0
                return True
    
        return False
    
    def is_3_black_crows(stock):
        # talib.CDL3BLACKCROWS
    
        # 三只乌鸦说明来自百度百科
        # 1. 连续出现三根阴线,每天的收盘价均低于上一日的收盘
        # 2. 三根阴线前一天的市场趋势应该为上涨
        # 3. 三根阴线必须为长的黑色实体,且长度应该大致相等
        # 4. 收盘价接近每日的最低价位
        # 5. 每日的开盘价都在上根K线的实体部分之内;
        # 6. 第一根阴线的实体部分,最好低于上日的最高价位
        #
        # 算法
        # 有效三只乌鸦描述众说纷纭,这里放宽条件,只考虑1和2
        # 根据前4日数据判断
        # 3根阴线跌幅超过4.5%
    
        h = attribute_history(stock, 4, '1d', ('close','open'), skip_paused=True, df=False)
        h_close = list(h['close'])
        h_open = list(h['open'])
    
        if len(h_close) < 4 or len(h_open) < 4:
            return False
     
        # 三根阴线
        if h_close[-4] > h_open[-4] 
            and (h_close[-1] < h_close[-2] and h_close[-2] < h_close[-3]) 
            and (h_close[-1] < h_open[-1] and h_close[-2]< h_open[-2] and h_close[-3] < h_open[-3]) 
            and h_close[-1] / h_close[-3] - 1 < -0.045 and get_current_data(stock)< h_close[-1]*0.995:
            return True
        return False
    '''
     # 一阳三阴
        if h_close[-4] > h_open[-4] 
            and (h_close[-1] < h_open[-1] and h_close[-2]< h_open[-2] and h_close[-3] < h_open[-3]):
            #and (h_close[-1] < h_close[-2] and h_close[-2] < h_close[-3]) 
            #and h_close[-1] / h_close[-3] - 1 < -0.045:
            return True
        return False
    '''  
    '''
    def is_3_black_crows(stock, data):
        # talib.CDL3BLACKCROWS
        his =  attribute_history(stock, 2, '1d', ('close','open'), skip_paused=True, df=False)
        closeArray = list(his['close'])
        closeArray.append(data[stock].close)
        openArray = list(his['open'])
        openArray.append(get_current_data()[stock].day_open)
    
        if closeArray[0]<openArray[0] and closeArray[1]<openArray[1] and closeArray[2]<openArray[2]:
            if closeArray[-1]/closeArray[0]-1>-0.045:
                his2 =  attribute_history(stock, 4, '1d', ('close','open'), skip_paused=True, df=False)
                closeArray1 = his2['close']
                if closeArray[0]/closeArray1[0]-1>0:
                    return True
        return False
    '''
    
    # 个股止损
    def stock_stop_loss(context, data):
        for stock in context.portfolio.positions.keys():
            cur_price = data[stock].close
            xi = attribute_history(stock, 2, '1d', 'high', skip_paused=True)
            ma = xi.max()
            if g.last_high[stock] < cur_price:
                g.last_high[stock] = cur_price
                
            threshold = get_stop_loss_threshold(stock, g.period)
            #log.debug("个股止损阈值, stock: %s, threshold: %f" %(stock, threshold))
            if cur_price < g.last_high[stock] * (1 - threshold):
                log.info("==> 个股止损, stock: %s, cur_price: %f, last_high: %f, threshold: %f" 
                    %(stock, cur_price, g.last_high[stock], threshold))
    
                position = context.portfolio.positions[stock]
                if close_position(position):
                    g.day_count = 0
    
    # 个股止盈
    def stock_stop_profit(context, data):
        for stock in context.portfolio.positions.keys():
            position = context.portfolio.positions[stock]
            cur_price = data[stock].close
            threshold = get_stop_profit_threshold(stock, g.period)
            #log.debug("个股止盈阈值, stock: %s, threshold: %f" %(stock, threshold))
            if cur_price > position.avg_cost * (1 + threshold):
                log.info("==> 个股止盈, stock: %s, cur_price: %f, avg_cost: %f, threshold: %f" 
                    %(stock, cur_price, g.last_high[stock], threshold))
    
                position = context.portfolio.positions[stock]
                if close_position(position):
                    g.day_count = 0
    
    # 获取个股前n天的m日增幅值序列
    # 增加缓存避免当日多次获取数据
    def get_pct_change(security, n, m):
        pct_change = None
        if security in g.pct_change.keys():
            pct_change = g.pct_change[security]
        else:
            h = attribute_history(security, n, unit='1d', fields=('close'), skip_paused=True)
            pct_change = h['close'].pct_change(m) # 3日的百分比变比(即3日涨跌幅)
            g.pct_change[security] = pct_change
        return pct_change
            
    # 计算个股回撤止损阈值
    # 即个股在持仓n天内能承受的最大跌幅
    # 算法:(个股250天内最大的n日跌幅 + 个股250天内平均的n日跌幅)/2
    # 返回正值
    def get_stop_loss_threshold(security, n = 3):
        pct_change = get_pct_change(security, 250, n)
        #log.debug("pct of security [%s]: %s", pct)
        maxd = pct_change.min()
        #maxd = pct[pct<0].min()
        avgd = pct_change.mean()
        #avgd = pct[pct<0].mean()
        # maxd和avgd可能为正,表示这段时间内一直在增长,比如新股
        bstd = (maxd + avgd) / 2
    
        # 数据不足时,计算的bstd为nan
        if not isnan(bstd):
            if bstd != 0:
                return abs(bstd)
            else:
                # bstd = 0,则 maxd <= 0
                if maxd < 0:
                    # 此时取最大跌幅
                    return abs(maxd)
    
        return 0.099 # 默认配置回测止损阈值最大跌幅为-9.9%,阈值高貌似回撤降低
    
    # 计算个股止盈阈值
    # 算法:个股250天内最大的n日涨幅
    # 返回正值
    def get_stop_profit_threshold(security, n = 3):
        pct_change = get_pct_change(security, 250, n)
        maxr = pct_change.max()
        
        # 数据不足时,计算的maxr为nan
        # 理论上maxr可能为负
        if (not isnan(maxr)) and maxr != 0:
            return abs(maxr)
        return 0.30 # 默认配置止盈阈值最大涨幅为20%
    
    # 获取股票n日以来涨幅,根据当前价计算
    # n 默认20日
    def get_growth_rate(security, n=20):
        lc = get_close_price(security, n)
        #c = data[security].close
        c = get_close_price(security, 1, '1m')
        
        if not isnan(lc) and not isnan(c) and lc != 0:
            return (c - lc) / lc
        else:
            log.error("数据非法, security: %s, %d日收盘价: %f, 当前价: %f" %(security, n, lc, c))
            return 0
    
    # 获取前n个单位时间当时的收盘价
    def get_close_price(security, n, unit='1d'):
        return attribute_history(security, n, unit, ('close'), True)['close'][0]
    
    # 开仓,买入指定价值的证券
    # 报单成功并成交(包括全部成交或部分成交,此时成交量大于0),返回True
    # 报单失败或者报单成功但被取消(此时成交量等于0),返回False
    def open_position(security, value):
        order = order_target_value_(security, value)
        if order != None and order.filled > 0:
            # 报单成功并有成交则初始化最高价
            cur_price = get_close_price(security, 1, '1m')
            g.last_high[security] = cur_price
            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.filled > 0:
                # 只要有成交,无论全部成交还是部分成交,则统计盈亏
                g.trade_stat.watch(security, order.filled, position.avg_cost, position.price)
    
            if order.status == OrderStatus.held and order.filled == order.amount:
                # 全部成交则删除相关证券的最高价缓存
                if security in g.last_high:
                    g.last_high.pop(security)
                else:
                    log.warn("last high price of %s not found" %(security))
                return True
    
        return False
    
    # 清空卖出所有持仓
    def clear_position(context):
        if context.portfolio.positions:
            log.info("==> 清仓,卖出所有股票")
            for stock in context.portfolio.positions.keys():
                position = context.portfolio.positions[stock]
                close_position(position)
    
    # 自定义下单
    # 根据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)
    
    
    # 过滤停牌股票
    def filter_paused_stock(stock_list):
        current_data = get_current_data()
        return [stock for stock in stock_list if not current_data[stock].paused]
    
    # 过滤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 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 last_prices[stock][-1] < current_data[stock].high_limit]
        #return [stock for stock in stock_list if stock in context.portfolio.positions.keys() 
        #    or last_prices[stock][-1] < current_data[stock].high_limit * 0.995]
    
    # 过滤跌停的股票
    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 last_prices[stock][-1] > current_data[stock].low_limit]
        #return [stock for stock in stock_list if last_prices[stock][-1] > current_data[stock].low_limit]
        #return [stock for stock in stock_list if stock in context.portfolio.positions.keys() 
        #    or last_prices[stock][-1] > current_data[stock].low_limit * 1.005]
        
    # 过滤黑名单股票
    def filter_blacklist_stock(context, stock_list):
        blacklist = get_blacklist()
        return [stock for stock in stock_list if stock not in blacklist]
    
    # 过滤创业版股票
    def filter_gem_stock(context, stock_list):
        return [stock for stock in stock_list if stock[0:3] != '300']
    
    # 过滤20日增长率为负的股票
    def filter_by_growth_rate(stock_list, n):
        return [stock for stock in stock_list if get_growth_rate(stock, n) > 0]
    
    # 股票评分
    def rank_stocks(data, stock_list):
        dst_stocks = {}
        for stock in stock_list:
            h = attribute_history(stock, 130, unit='1d', fields=('close', 'high', 'low'), skip_paused=True)
            low_price_130 = h.low.min()
            high_price_130 = h.high.max()
    
            avg_15 = data[stock].mavg(15, field='close')
            cur_price = data[stock].close
    
            #avg_15 = h['close'][-15:].mean()
            #cur_price = get_close_price(stock, 1, '1m')
    
            score = (cur_price-low_price_130) + (cur_price-high_price_130) + (cur_price-avg_15)
            #score = ((cur_price-low_price_130) + (cur_price-high_price_130) + (cur_price-avg_15)) / cur_price
            dst_stocks[stock] = score
            
        df = pd.DataFrame(dst_stocks.values(), index=dst_stocks.keys())
        df.columns = ['score']
        df = df.sort(columns='score', ascending=True)
        return df.index
    
    '''
    # 过滤新股
    def filter_new_stock(stock_list):
        stocks = get_all_securities(['stock'])
        stocks = stocks[(context.current_dt.date() - stocks.start_date) > datetime.timedelta(60)].index
    '''
    
    # 选股
    # 选取指定数目的小市值股票,再进行过滤,最终挑选指定可买数目的股票
    def pick_stocks(context, data):
        q = None
        if g.pick_by_pe:
            if g.pick_by_eps:
                q = query(valuation.code).filter(
                    indicator.eps > g.min_eps,
                    valuation.pe_ratio > g.min_pe,
                    valuation.pe_ratio < g.max_pe
                ).order_by(
                    valuation.market_cap.asc()
                ).limit(
                    g.pick_stock_count
                )
            else:
                q = query(valuation.code).filter(
                    valuation.pe_ratio > g.min_pe,
                    valuation.pe_ratio < g.max_pe
                ).order_by(
                    valuation.market_cap.asc()
                ).limit(
                    g.pick_stock_count
                )
        else:
            if g.pick_by_eps:
                q = query(valuation.code).filter(
                    indicator.eps > g.min_eps
                ).order_by(
                    valuation.market_cap.asc()
                ).limit(
                    g.pick_stock_count
                )
            else:
                q = query(valuation.code).order_by(
                    valuation.market_cap.asc()
                ).limit(
                    g.pick_stock_count
                )
        
        df = get_fundamentals(q)
        stock_list = list(df['code'])
    
        if g.filter_gem:
            stock_list = filter_gem_stock(context, stock_list)
            
        if g.filter_blacklist:
            stock_list = filter_blacklist_stock(context, stock_list)
            
        stock_list = filter_paused_stock(stock_list)
        stock_list = filter_st_stock(stock_list)
        stock_list = filter_limitup_stock(context, stock_list)
        stock_list = filter_limitdown_stock(context, stock_list)
    
        # 根据20日股票涨幅过滤效果不好,故注释
        #stock_list = filter_by_growth_rate(stock_list, 15)
        
        if g.is_rank_stock:
            if len(stock_list) > g.rank_stock_count:
                stock_list = stock_list[:g.rank_stock_count]
    
            #log.debug("评分前备选股票: %s" %(stock_list))
            if len(stock_list) > 0:
                stock_list = rank_stocks(data, stock_list)
            #log.debug("评分后备选股票: %s" %(stock_list))
        
        # 选取指定可买数目的股票
        if len(stock_list) > g.buy_stock_count:
            stock_list = stock_list[:g.buy_stock_count]
        return stock_list
    
    # 根据待买股票创建或调整仓位
    # 对于因停牌等原因没有卖出的股票则继续持有
    # 始终保持持仓数目为g.buy_stock_count
    def adjust_position(context, buy_stocks):
        for stock in context.portfolio.positions.keys():
            if stock not in buy_stocks:
                log.info("stock [%s] in position is not buyable" %(stock))
                position = context.portfolio.positions[stock]
                close_position(position)
            else:
                log.info("stock [%s] is already in position" %(stock))
        
        # 根据股票数量分仓
        # 此处只根据可用金额平均分配购买,不能保证每个仓位平均分配
        position_count = len(context.portfolio.positions)
        if g.buy_stock_count > position_count:
            value = context.portfolio.cash / (g.buy_stock_count - position_count)
    
            for stock in buy_stocks:
                if context.portfolio.positions[stock].total_amount == 0:
                    if open_position(stock, value):
                        if len(context.portfolio.positions) == g.buy_stock_count:
                            break
  • 相关阅读:
    python字典
    python元组
    python list列表
    deepin常用操作
    Be a child.Be a man...
    “夹心阶层”——面对高昂的房价,要面对现实,广州,除了劳动力便宜,什么都贵。
    男人一生中16件事情(转载)
    被老板臭骂了一顿,但受益匪浅。
    陪伴
    高品质生活
  • 原文地址:https://www.cnblogs.com/xiaohengheng/p/7686376.html
Copyright © 2020-2023  润新知