ricequant / rqalpha

A extendable, replaceable Python algorithmic backtest && trading framework supporting multiple securities
http://rqalpha.io
Other
5.38k stars 1.61k forks source link

'NoneType' object has no attribute 'open' #595

Closed 349286991 closed 3 years ago

349286991 commented 3 years ago

1. RQAlpha的版本4.2.4

2. Python的版本 3.8

3. 是Windows

4. 源码如下

import sys
from rqalpha.apis import *
from rqalpha import run_func
from decimal import *
import ast
import MySQLdb

aginCash=8000000000
startDate='2019-01-02'
endDate='2019-02-01'
codeType=''
CYCLE="M"
CYCLE_NUM= 6
codeStr= ""
memberStr="{'ZJQH161033162103000':0.5,'YDQH161032278909000':0.5}"
ret=""

for i in range(1, len(sys.argv)):
    if i == 1:
        aginCash = int(sys.argv[i])
    if i == 2:
        startDate = sys.argv[i]
    if i == 3:
        endDate = sys.argv[i]
    if i == 4:
        codeType = sys.argv[i]
    if i == 5:
        CYCLE = sys.argv[i]
    if i == 6:
        CYCLE_NUM = int(sys.argv[i])
    if i == 7:
        codeStr = sys.argv[i]
    if i == 8:
        memberStr = sys.argv[i]

print(aginCash,startDate,endDate,codeType,CYCLE,CYCLE_NUM,codeStr)

memberinfo= ast.literal_eval(memberStr)

config = {
  "base": {
    "start_date": startDate,
    "end_date": endDate,
    "benchmark": "000300.XSHG",
    "accounts": {
        "future": aginCash
    }
  },
  "extra": {
    "log_level": "info",
  },
  "mod": {
    "sys_analyser": {
      "enabled": True,
      "plot": False,
    },
  }
}

db = MySQLdb.connect("127.0.0.1", "root", "root", "quant_test", port=33006, charset='utf8' )

# 使用cursor()方法获取操作游标
cursor = db.cursor()

# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递
def init(context):

    context.codeType = codeType
    context.code = codeStr
    context.codeDic = {}
    context.memberDic = {}
    context.memberInfoDic = memberinfo
    context.Vol = {}

    context.MBuy = {}
    context.MSell = {}
    context.EBuy = {}
    context.ESell = {}

# 你选择的期货数据更新将会触发此段逻辑,例如日线或分钟线更新
def open_auction (context, bar_dict):
    members = context.memberInfoDic.keys()
    #sql = "SELECT * FROM crawler_gain_loss_analysis  WHERE TRADE_DATE = " +"'"+bar_dict.dt.year+"-"+bar_dict.dt.month+"-"+bar_dict.dt.day+"'"
    sql1 = ""
    sql = ''
    date = str(bar_dict.dt.year)+"-"+str(bar_dict.dt.month)+"-"+str(bar_dict.dt.day)
    if codeType != '':
        sql1 = "SELECT * FROM crawler_gain_loss_analysis  WHERE TRADE_DATE ='{}' and CODE_TYPE ='{}' and MEMBER in (%s)"
        sql = sql1.format(date, context.codeType)  # 转化后的sql语句
    elif codeStr != '':
        sql1 = "SELECT * FROM crawler_gain_loss_analysis  WHERE TRADE_DATE ='{}' and CODE ='{}' and MEMBER in (%s)"
        sql = sql1.format(date, context.code)  # 转化后的sql语句
    elif codeStr == '' and codeType == '':
        sql1 = "SELECT * FROM crawler_gain_loss_analysis  WHERE TRADE_DATE ='{}' and MEMBER in (%s)"
        sql = sql1.format(date)  # 转化后的sql语句
    cursor.execute(sql % ", ".join(map(lambda x:"'%s'"% x,members)) )
    results = cursor.fetchall()
    # 迭代当日交易
    for data in results:
        # 合约
        code = data[1]
        # 会员
        member = data[4]
        # 会员倍数
        member_bs = 0
        # 当前会员比例
        member_bl = context.memberInfoDic[member]*2

        m_num = 0
        e_num = 0

        # 获得会员倍数
        if member in context.memberDic.keys():
            member_bs = context.memberDic[member].get("member_bs")
        else:
            # 查询倍数
            membersql1 = "select * from crawler_member where MEMBER_CODE = '{}'"
            membersql = membersql1.format(member)  # 转化后的sql语句
            cursor.execute(membersql)
            memberBean = cursor.fetchall()
            if len(memberBean) == 1:
                context.memberDic[member] = {'member_bs': memberBean[0][12]}
                member_bs = memberBean[0][12]

        # 合约存在
        if code in context.codeDic.keys():
            # 查出今日原有的

            # 多单
            m_num = context.codeDic[code].get("m_num")
            # 空单
            e_num = context.codeDic[code].get("e_num")

            m_BS_num = Decimal(str(data[9]))*Decimal(str(member_bs))*Decimal(str(member_bl)).quantize(Decimal('0.00'))
            e_BS_num = Decimal(str(data[15]))*Decimal(str(member_bs))*Decimal(str(member_bl)).quantize(Decimal('0.00'))

            context.codeDic[code]['m_num'] = Decimal(str(m_num)) + Decimal(str(m_BS_num))

            context.codeDic[code]['e_num'] = Decimal(str(e_num)) + Decimal(str(e_BS_num))

        # 合约不存在
        else:
            context.codeDic[code]={}
            m_BS_num = Decimal(str(data[9]))*Decimal(str(member_bs))*Decimal(str(member_bl)).quantize(Decimal('0.00'))
            context.codeDic[code].update({'m_num': m_BS_num})

            e_BS_num = Decimal(str(data[15])) * Decimal(str(member_bs))*Decimal(str(member_bl)).quantize(Decimal('0.00'))
            context.codeDic[code].update({'e_num': e_BS_num})

    # 开始交易
    for k, v in context.codeDic.items():
        code = k
        obj = v
        m_num = int(obj.get('m_num')/100)
        e_num = int(obj.get('e_num')/100)

        have_m_num = get_position(code, 'LONG').quantity
        have_e_num = get_position(code, 'SHORT').quantity

        buy_sell_m(have_m_num, m_num, code, context)

        buy_sell_e(have_e_num, e_num, code, context)

def handle_tick(context, tick):
    # 继续交易上次未交易完成的订单
    #多单买入
    for k in list(context.MBuy.keys()):
        v=context.MBuy[k]
        otherCode=v['order_book_id']
        amount=v['quantity']
        # 删除已经处理的订单
        context.MBuy.pop(k)
        logger.info("再次多单买入"+str(otherCode)+"数量"+str(amount))
        buy_sell_m(0,amount,otherCode,context)

    # 平买仓
    for k in list(context.MSell.keys()):
        v = context.MSell[k]
        otherCode=v['order_book_id']
        amount=v['quantity']
        # 删除已经处理的订单
        context.MSell.pop(k)
        # logger.info("再次多单卖出" + str(otherCode) + "数量" + str(amount))
        buy_sell_m(amount,0,otherCode,context)

    # 空单买入
    for k in list(context.EBuy.keys()):
        v = context.EBuy[k]
        otherCode=v['order_book_id']
        amount=v['quantity']
        # 删除已经处理的订单
        context.EBuy.pop(k)
        # logger.info("再次空单买入" + str(otherCode) + "数量" + str(amount))
        buy_sell_e(0,amount,otherCode,context)

    # 平空仓
    for k in list(context.ESell.keys()):
        v = context.ESell[k]
        otherCode=v['order_book_id']
        amount=v['quantity']
        # 删除已经处理的订单
        context.ESell.pop(k)
        #logger.info("再次空单卖出" + str(otherCode) + "数量" + str(amount))
        buy_sell_e(amount,0,otherCode,context)

def buy_sell_m(MVol,nowMVol,code,context):

    # 多单持仓量<当前多单持仓量
    if MVol < nowMVol:
        # 开单买入
        amount = nowMVol - MVol
        #logger.info("多单买入" + str(code) + "数量" + str(amount))
        ret = buy_open(code, amount)
        #logger.info(ret)
        if type(ret) is list:
            return
        if ret.message.strip()!='':
            context.MBuy[ret.order_id]={'order_book_id':ret.order_book_id , 'quantity':ret.quantity}
    # 多单持仓量>当前多单持仓量
    if MVol > nowMVol:
        # 平买仓
        amount=MVol - nowMVol
        #logger.info("多单卖出" + str(code) + "数量" + str(amount))
        haveamount = get_position(code, 'LONG').quantity
        ret = None
        if haveamount >= amount :
            ret = sell_close(code, amount)
        elif haveamount != 0:
            ret = sell_close(code, haveamount)
        else:
            return
        #logger.info(ret)
        if type(ret) is list:
            return
        if ret.message.strip()!='':
            context.MSell[ret.order_id]={'order_book_id':ret.order_book_id , 'quantity':ret.quantity}

def buy_sell_e(EVol,nowEVol,code,context):

    # 空单持仓量<当前空单持仓量
    if EVol < nowEVol:
        # 空单买入
        amount=nowEVol - EVol
        # logger.info("空单买入" + str(code) + "数量" + str(amount))
        ret=sell_open(code, amount)
        #logger.info(ret)
        if type(ret) is list:
            return
        if ret.message.strip()!='':
            context.EBuy[ret.order_id] = {'order_book_id': ret.order_book_id, 'quantity': ret.quantity}
    # 空单持仓量>当前空单持仓量
    if EVol > nowEVol:
        # 平空仓
        amount=EVol - nowEVol
        # logger.info("空单卖出" + str(code) + "数量" + str(amount))
        haveamount=get_position(code, 'SHORT').quantity
        ret=None
        if haveamount>=amount:
            ret=buy_close(code, amount)
        elif haveamount!=0:
            ret = buy_close(code, haveamount)
        else:
            return
        #logger.info(ret)
        if type(ret) is list:
            return
        if ret.message.strip()!='':
            context.ESell[ret.order_id]={'order_book_id':ret.order_book_id , 'quantity':ret.quantity}

results = run_func(init=init, open_auction=open_auction,handle_tick=handle_tick, config=config)
# report = results["sys_analyser"]
# ret=report["summary"]
# #print("member",member)
#
# CASH=ret["FUTURE"]
# #print("CASH",ret["FUTURE"])
#
# START_DATE=ret["start_date"]
# #print("START_DATE",ret["start_date"])
#
# END_DATE=ret["end_date"]
# #print("END_DATE",ret["end_date"])
#
# MAX_DRAWDOWN=ret["max_drawdown"]
# #print("MAX_DRAWDOWN",ret["max_drawdown"])
#
# INCOME=ret["total_returns"]
# #print("INCOME",ret["total_returns"])
#
# INCOME_YEAR=ret["annualized_returns"]
# #print("INCOME_YEAR",ret["annualized_returns"])
#
# SHARPE=ret["sharpe"]
# #print("SHARPE",ret["sharpe"])
# #评分=0.3*年化率+0.4*夏普率+0.3*最大回撤率
# getcontext().prec = 6
# v1=Decimal('0.3')*Decimal(str(INCOME_YEAR))
# v2=Decimal('0.4')*Decimal(str(SHARPE))
# v3=Decimal('0.3')*Decimal(str(MAX_DRAWDOWN))
# SCORING=v1+v2+v3
# #print("SCORING",SCORING)
#
# def insert_data(dbName,data_dict):
#
#     try:
#
#         data_values = "(" + "%s," * (len(data_dict)) + ")"
#         data_values = data_values.replace(',)', ')')
#
#         dbField = data_dict.keys()
#         dataTuple = tuple(data_dict.values())
#         dbField = str(tuple(dbField)).replace("'",'')
#
#         sql = """ insert into %s %s values %s """ % (dbName,dbField,data_values)
#         params = dataTuple
#         cursor.execute(sql, params)
#         db.commit()
#         cursor.close()
#         ret="success"
#         print("success")
#         return 1
#
#     except Exception as e:
#         ret = "error"
#         print("error")
#         return 0
# dbName="crawler_gain_loss_analysis_ret"
# id = str(CYCLE) + '_' + str(CYCLE_NUM) + '_' + str(START_DATE) + '_' + str(END_DATE)
#
# data_dict = {
#             "ID":id,
#             "CODE": codeStr,
#             "CASH": CASH,
#             "START_DATE": START_DATE,
#             "END_DATE": END_DATE,
#             "MAX_DRAWDOWN": MAX_DRAWDOWN,
#             "INCOME": INCOME,
#             "INCOME_YEAR": INCOME_YEAR,
#             "SHARPE": SHARPE,
#             "CODE_TYPE": codeType,
#             "CYCLE": CYCLE,
#             "CYCLE_NUM": CYCLE_NUM,
#             "CREATE_BY": "ww",
#             "CREATE_DATE": datetime.datetime.now().strftime('%Y-%m-%d'),
#             "DATA_STATU": "valid",
#             "SCORING": SCORING,
#             "VAL1":"ret"
#         }
# result = insert_data(dbName, data_dict)
# print(ret)
#
#

5. 错误堆栈日志信息

C:\Users\being\anaconda3\python.exe "D:\soft\PyCharm Community Edition 2020.2.3\plugins\python-ce\helpers\pydev\pydevd.py" --multiproc --qt-support=auto --client 127.0.0.1 --port 60340 --file D:/pythonProject/test/backTrader.py pydev debugger: process 42556 is connecting

Connected to pydev debugger (build 202.7660.27) 8000000000 2019-01-02 2019-02-01 M 6 [2020-12-30 15:02:57.120546] WARN: system_log: rqdatac 初始化失败,部分扩展 API 可能无法使用,错误信息:user auth failed! code: 202 message: 该 License 已过期。您可以访问 https://www.ricequant.com/welcome/rqdata 获取 rqdatac [2020-12-30 15:02:57.176409] WARN: user_system_log: 配置'base.benchmark'已被弃用,使用'mod.sys_analyser.benchmark'代替 [2019-01-18 15:30:00.000000] WARN: user_system_log: IC1901 已退市/交割,系统自动平仓 [2019-01-18 15:30:00.000000] WARN: user_system_log: IC1901 已退市/交割,系统自动平仓 [2019-01-18 15:30:00.000000] WARN: user_system_log: IH1901 已退市/交割,系统自动平仓 [2019-01-18 15:30:00.000000] WARN: user_system_log: IH1901 已退市/交割,系统自动平仓 [2019-01-18 15:30:00.000000] WARN: user_system_log: IF1901 已退市/交割,系统自动平仓 [2019-01-21 00:00:00.000000] ERROR: user_system_log: 策略运行产生异常 Traceback (most recent call last): File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\strategy.py", line 99, in open_auction self._open_auction(self._user_context, bar_dict) File "D:/pythonProject/test/backTrader.py", line 166, in open_auction buy_sell_m(have_m_num, m_num, code, context) File "D:/pythonProject/test/backTrader.py", line 222, in buy_sell_m ret = buy_open(code, amount) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\execution_context.py", line 104, in wrapper return func(*args, kwargs) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\utils\arg_checker.py", line 440, in api_rule_check_wrapper return func(*args, *kwargs) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\utils\functools.py", line 104, in wrapper return impl(args, kwargs) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\mod\rqalpha_mod_sys_accounts\api\api_future.py", line 188, in future_buy_open return _submit_order(id_or_ins, amount, SIDE.BUY, POSITION_EFFECT.OPEN, cal_style(price, style)) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\mod\rqalpha_mod_sys_accounts\api\api_future.py", line 59, in _submit_order price = env.get_last_price(order_book_id) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\environment.py", line 149, in get_last_price return self.data_proxy.get_last_price(order_book_id) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\data\data_proxy.py", line 261, in get_last_price return float(self._price_board.get_last_price(order_book_id)) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\data\bar_dict_price_board.py", line 33, in get_last_price return self._get_bar(order_book_id).last File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\model\bar.py", line 51, in last = property(lambda self: self.open) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\model\bar.py", line 48, in open = property(fget=lambda self: self._tick.open) AttributeError: 'NoneType' object has no attribute 'open'

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\main.py", line 214, in run executor.run(bar_dict) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\executor.py", line 52, in run self._split_and_publish(event) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\executor.py", line 98, in _split_and_publish self._env.event_bus.publish_event(e) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\events.py", line 42, in publish_event if listener(event): File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\strategy.py", line 34, in wrapper return func(*args, **kwargs) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\strategy.py", line 99, in open_auction self._open_auction(self._user_context, bar_dict) File "C:\Users\being\anaconda3\lib\site-packages\rqalpha\core\execution_context.py", line 93, in exit raise user_exc rqalpha.utils.exception.CustomException: 'NoneType' object has no attribute 'open' [2019-01-21 00:00:00.000000] ERROR: user_system_log: 'NoneType' object has no attribute 'open'

Process finished with exit code 0

mar-heaven commented 3 years ago

@349286991 使用insert code 上传代码

Cuizi7 commented 3 years ago

已在 4.4.0 版本修复,