小白天天向上 2021-06-16 13:15 采纳率: 0%
浏览 91

通达信布林带策略转化成掘金量化交易,遇到一些问题需请教热心网友Debug

# coding=utf-8
from __future__ import print_function, absolute_import
from gm.api import *
import pandas as pd
import talib as tb
import numpy as np
import math as mh


'''
本策略以BULL中轨线5min(即300s频度)bar数据建立双均线模型,
短周期为short,长周期为60,当短期均线由上向下穿越长期均线时做空,
当短期均线由下向上穿越长期均线时做多,每次开仓前先平掉所持仓位,再开仓。
注:为了适用于仿真和实盘,在策略中增加了一个“先判断是否平仓成功再开仓”的判断逻辑,以避免出现未平仓成功,可用资金不足的情况。
回测数据为:SHFE.rb2101的60s频度bar数据
回测时间为:2020-04-01 09:00:00到2020-05-31 15:00:00
'''


def init(context):                                              # 定义参数
    context.shorttime = '300s'                                      # 短周期,5min
    context.longtime= '1500s'                                       # 长周期,15min
    context.long1 = 12                                          # 短周期取样频率
    context.period1 = context.long1 + 1                         # 订阅数据滑窗长度
    context.long2 = 4                                           # 长周期取样频率
    context.period2 = context.long2 + 1                         # 订阅数据滑窗长度

    context.BandWidth = 2                                       # 带宽率
    context.Angle1 = 2                                          # 上涨均线角度
    context.Angle2 = -2                                         # 下跌均线角度
    context.maPeriod1 = 12                                      # 计算BOLL布林线中轨的参数
    context.stdPeriod1 = 26                                     # 计算BOLL 标准差的参数
    context.stdRange1 = 2.6                                     # 计算BOLL 上下轨和中轨距离的参数
    context.maPeriod2 = 4                                       # 计算BOLL布林线中轨的参数
    context.stdPeriod2 = 8                                      # 计算BOLL 标准差的参数
    context.stdRange2 = 2.6                                     # 计算BOLL 上下轨和中轨距离的参数

    context.symbol = 'DCE.i2109'                                 # 订阅交易标的


    context.open_long = False                                    # 开多单标记
    context.open_short = False                                   # 开空单标记
    
    subscribe(context.symbol, frequency = context.shorttime, count = context.period1)         # 订阅短周期行情
    subscribe(context.symbol, frequency = context.longtime,  count = context.period2)         # 订阅长周期行情
'''
    AS:=(C*3+O+H+L)/6;
    AS1:=0.618*REF(AS,1);
    AS2:=0.382*REF(AS,2);
    AS3:=0.236*REF(AS,3);
    AS4:=0.146*REF(AS,4);
    NEWPRICE1:=(AS+AS1+AS2+AS3+AS4)/2.382;
    '''
'''
    在通达信中有一个REF(N)函数,用来表示滞后N期的数据,REF(CLOSE,1)就表示滞后1期的收盘价。转化到python中,需要用索引的方式直接取出前一期数据。
    比如:REF(CLOSE,1)在python中表示为CLOSE.iloc[-2],意思为CLOSE的倒数第二个元素,即CLOSE的前一期元素。
    (因为CLOSE的最后一个元素是当前日期的数据,倒数第二个元素才是前一日的数据,所以选择倒数第二个元素)
Tips : iloc的用法
iloc表示索引引用方法,使用方式为:df.iloc[m,n],表示df第m行n列的数据。如果df是一维数据,则df.iloc[n]表示df第n个数据。
    '''
def newprice1(price_frequency, price_count):
    prices = context.data(context.symbol, price_frequency, price_count, fields='open,close,high,low')
    High = context.data['high']          # 最高价
    Low = context.data['low']           # 最低价
    Close = context.data['close']               # 收盘价
    Open = context.data['open']                 # 开盘价
    AS = (Close*3 + Open + High + Low) / 6      # 拟合成本价格
    AS1 = 0.618 * AS.iloc[-2] 
    AS2 = 0.382 * AS.iloc[-3] 
    AS3 = 0.382 * AS.iloc[-4] 
    AS4 = 0.382 * AS.iloc[-5] 
    result1 =  (AS+AS1+AS2+AS3+AS4)/2.382
    return result1

'''
    NEWPRICE2:=IF(C>REF(C,1),0.618*C+0.382*H,0.618*C+0.382*L);
    '''
def newprice2(price_frequency,price_count):
    prices = context.data(context.symbol, price_frequency, price_count, fields='open,close,high,low')
    High = context.data['high']          # 最高价
    Low = context.data['low']           # 最低价
    Close = context.data['close']               # 收盘价
    Open = context.data['open']                 # 开盘价
    if (Close.iloc[-1] > Close.iloc[-2]) :
        result2 =  0.618* Close + 0.382 * High
    else :
        result2 = 0.618* Close + 0.382 * Low
    return result2
'''
    MA2:=MA(NEWPRICE2,21);
    '''
    # 利用talib库计算周期均线
def newprice2_avg(price_frequency,price_count,N):
    price = newprice2(price_frequency,price_count,N)
    avg =  price.rolling(N).mean()
    return avg

def on_bar(context, bars):     # 获取数据滑窗,只要在init里面有订阅,在这里就可以取的到,返回值是pandas.DataFrame
    # 获取通过subscribe订阅的数据,取出是dataframe格式
    data1 = context.data(context.symbol, context.shorttime, context.period1, fields='open,close,high,low')
    data2 = context.data(context.symbol, context.longtime,  context.period2, fields='open,close,high,low')

'''
    # BOLL:BOLL带指标计算
    # 中轨线 = N日收盘价平均值
    # 上轨线 = 中轨线 + N日收盘价标准差
    # 下轨线 = 中轨线 - N日收盘价标准差
    {中轨}
    MID:=EMA(NEWPRICE1,NSHORT);
    中轨:MID,COLORWHITE,LINETHICK2;
    STD_WIDTH:=2.6*STD(MID,MLONG);
    {上轨}
    UPPER:=MID+STD_WIDTH;
    上轨:UPPER,COLORYELLOW,LINETHICK2;
    {下轨}
    LOWER:=MID-STD_WIDTH;
    下轨:LOWER,COLORGREEN,LINETHICK2;
    {轨道收缩率}
    BAND_RATE:=STD_WIDTH/MID*1000;
    带宽比:BAND_RATE,NODRAW;
    MIDANGLE:=ATAN((MID/REF(MID,1)-1)*100)*180/3.1416;
    MID角度:MIDANGLE,COLORWHITE,NODRAW;
    '''
    # 计算boll中轨价格
    N1 = newprice1(context.shorttime, context.period1)  
    BollMid = talib.EMA(N1,context.period1) 
    BollStd = context.stdRange1 * N1.rolling(context.stdPeriod1).std()
    # 计算boll的上下界
    BollUpper =  BollMid + BollStd
    BollBottom = BollMid - BollStd
    # 计算带宽比
    BandRate = BollStd / BollMid * 100
    # 计算中轨均线角度
    MidAngle = math.atan(BollMid/BollMid[-1])  # atan()是不能直接访问的,需要导入 math 模块,然后通过 math 静态对象调用该方法。

'''
    {布林带下降趋势,图标15-小人逃跑,平仓或做空}
    S1:=MID<REF(MID,1) AND  NEWPRICE2<MA2  ;
    S2:=MIDANGLE<ANGLE2;
    DRAWICON(S1 AND S2  ,MID*0.999,15);

    {布林带上降趋势,图标9-金钱袋,开仓仓或做多}
    B1:MID>REF(MID,1) AND  NEWPRICE2>MA2 AND NEWPRICE1>MID AND C>MID,NODRAW;
    B2:MIDANGLE>ANGLE1,NODRAW;
    BUYCONDITION:=B1 AND B2 ;
    DRAWICON(BUYCONDITION,MID*1.002,9);
    '''
    # SellCondition 卖出条件
    S1 = BollMid < BollMid[-1] and newprice2 < newprice2_avg(contex.shorttime,context.period1,21)
    S2 = MidAngle < context.Angle2 
    SellCondition = S1 and S2
    

    # BuyCondition 买入条件
    B1 = BollMid > BollMid[-1] and newprice2 > newprice2_avg(contex.shorttime,context.period1,21) and newprice1>BollMid and data['close'] > BollMid
    B2 = MidAngle > context.Angle1
    BuyCondition = B1 and B2
    
    
    # 查询持仓
    position_long = context.account().position(symbol=context.symbol, side=1)   # PositionSide_Long == 1,多单
    position_short = context.account().position(symbol=context.symbol, side=2)   # PositionSide_Short == 1,空单

    # 做空
    if SellCondition.iloc[-2] < SellCondition.iloc[-1]  and SellCondition.iloc[-2] == 0 :
        # 无多仓情况下,直接开空
        if not position_long:
            order_volume(symbol=context.symbol, volume=1, side=OrderSide_Sell, position_effect=PositionEffect_Open, order_type=OrderType_Market)
            print(context.symbol, '以市价单调空仓到仓位')

        # 有多仓情况下,先平多,再开空(开空命令放在on_order_status里面)
        else:
            context.open_short = True
            # 以市价平多仓
            order_volume(symbol=context.symbol, volume=1, side=OrderSide_Sell, position_effect=PositionEffect_Close, order_type=OrderType_Market)
            print(context.symbol, '以市价单平多仓')

    # 做多
    if BuyCondition.iloc[-2] < BuyCondition.iloc[-1] and BuyCondition.iloc[-2] == 0:
        # 无空仓情况下,直接开多
        if not position_short:
            order_volume(symbol=context.symbol, volume=1, side=OrderSide_Buy, position_effect=PositionEffect_Open, order_type=OrderType_Market)
            print(context.symbol, '以市价单调多仓到仓位')

        # 有空仓的情况下,先平空,再开多(开多命令放在on_order_status里面)
        else:
            context.open_long = True
            # 以市价平空仓
            order_volume(symbol=context.symbol, volume=1, side=OrderSide_Buy, position_effect=PositionEffect_Close, order_type=OrderType_Market)
            print(context.symbol, '以市价单平空仓')


def on_order_status(context, order):
    # 查看下单后的委托状态
    status = order['status']
    # 成交命令的方向
    side = order['side']
    # 交易类型
    effect = order['position_effect']
    # 当平仓委托全成后,再开仓
    if status == 3:
        # 以市价开空仓,需等到平仓成功无仓位后再开仓
        # 如果无多仓且side=2(说明平多仓成功),开空仓
        if effect == 2 and side == 2 and context.open_short:
            context.open_short = False
            order_volume(symbol=context.symbol, volume=1, side=OrderSide_Sell, position_effect=PositionEffect_Open, order_type=OrderType_Market)
            print(context.symbol, '以市价单调空仓到仓位')
        # 以市价开多仓,需等到平仓成功无仓位后再开仓
        # 如果无空仓且side=1(说明平空仓成功),开多仓
        if effect == 2 and side == 1 and context.open_long:
            context.open_long = False
            order_volume(symbol=context.symbol, volume=1, side=OrderSide_Buy, position_effect=PositionEffect_Open, order_type=OrderType_Market)
            print(context.symbol, '以市价单调多仓到仓位')

if __name__ == '__main__':
    '''
        strategy_id策略ID,由系统生成
        filename文件名,请与本文件名保持一致
        mode实时模式:MODE_LIVE
        mode回测模式:MODE_BACKTEST
        token绑定计算机的ID,可在系统设置-密钥管理中生成
        backtest_start_time回测开始时间
        backtest_end_time回测结束时间
        backtest_adjust股票复权方式不复权:ADJUST_NONE前复权:ADJUST_PREV后复权:ADJUST_POST
        backtest_initial_cash回测初始资金
        backtest_commission_ratio回测佣金比例
        backtest_slippage_ratio回测滑点比例
    '''
    run(strategy_id='1c566dba-c345-11eb-9923-b07b25324c88',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='{{token}}',
        backtest_start_time='2021-01-01 09:00:00',
        backtest_end_time='2021-05-31 15:00:00',
        backtest_adjust=ADJUST_NONE,
        backtest_initial_cash=10000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

  • 写回答

1条回答 默认 最新

  • 有问必答小助手 2021-06-21 11:52
    关注

    你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,目前超出我们的服务范围,暂时无法为您解答。

    首次提问人员可免费体验一次有问必答服务。目前首次提问的问题服务范围为:编程语言、Java开发、python、数据库、前端开发 领域专业技术问题,为您提供问题的解决思路和指导。不提供源码代写、项目文档代写、论文代写、作业代写、安装包资源发送或安装、软件使用指导等服务。

    我们后续会持续优化,扩大我们的服务范围,为您带来更好地服务。

    评论

报告相同问题?

悬赏问题

  • ¥15 Rs232电路无法收发数据,求帮助
  • ¥15 百度cookie扫码登录器
  • ¥15 微机原理汇编语言debug调试实验
  • ¥23 matlab可以把相图转换为庞加莱映射吗
  • ¥20 有偿,学生成绩信息管理系统
  • ¥15 Arduino电机和openmv连接异常
  • ¥15 Arcgis河网分级报错
  • ¥200 java+appium2.1+idea
  • ¥20 请帮我做一个EXE的去重TXT文本
  • ¥15 工价表引用工艺路线,应如何制作py和xml文件