예제 #1
0
class model_future_detect_multi(object):

    def __init__(self):
        # 统一参数
        self.config = {}  # 配置参数字典表
        self.deltaLimit = 0.8  # 浮动/标准差
        self.iniAmount = 250000  # 单边50万
        self.stopTimeLine = 5  # 止损时间线
        self.batchNum = 2
        self.banCodeList = [] # 暂时无权限操作的code

        self.isWorking = False
        self.ctpuser = '******'
        #
        self.topUse = True  # 启用定时统计列表
        self.isCTPUse = False  # 是否启用CTP接口(并区分
        self.isAutoAlterPosition = True # 到期是否自动调仓
        self.isDeadCheck = True # 是否启用自动检查并交易沉淀品种

        self.topFilter = ' count>10 '
        self.sameLimit = 3  # 同一code允许出现次数
        self.topNumbers = 30  # 最大新币对 (监控币对还包括历史10和未平仓对)
        self.minRate = -0.03 # 最低收益率

        self.orderFormTest = 'future_orderForm_test'
        self.topTableName = 'train_total_s2'
        self.methodName = 'mul'  # 策略名称
        #
        self.future_Map = []
        self.noneUsed = []  # 不再继续的商品对

    def pool(self):
        pool = Pool(processes=6)
        shareDict = Manager().list([])
        CTP = None
        # 初始化codes列表
        if self.topUse:
             self.filterCodes()

        for codes in self.seperate():
            #if "" in codes or "AP" not in codes: continue
            #self.start(codes, shareDict, CTP)
            try:
                pool.apply_async(self.start, (codes, shareDict, CTP))
                time.sleep(3)
                pass
            except Exception as e:
                print('error', e)
                continue

        pool.close()
        pool.join()

        # 同时统计未平仓的对,加入监测,待平仓后不再开仓
    def filterCodes(self):
        # 查询每周统计表
        Top = train_total()
        Top.tablename = self.topTableName
        self.future_Map = Top.last_top(num=self.topNumbers, filter=self.topFilter, maxsames=self.sameLimit,
                                       minRate=self.minRate)
        num0 = len(self.future_Map)
        Record = future_orderForm()
        if not self.isWorking:  Record.tablename = self.orderFormTest

        # 添加top10
        codesList = [[c[0], c[1]] for c in self.future_Map]
        for map in Record.topCodes(method=self.methodName, toptable=self.topTableName,batchNum=self.batchNum):
            if not map[0:2] in codesList:
                self.future_Map.append(map)

        num1 = len(self.future_Map) - num0

        # 添加未平仓,并不再开仓
        codesList = [[c[0], c[1]] for c in self.future_Map]
        for map in Record.currentOpenCodes(method=self.methodName, batchNum=self.batchNum):
            if not map[0:2] in codesList and map[0]:
                self.future_Map.append(map[:-1])
                self.noneUsed.append(map[0:2])

        # 开盘时调仓处理
        if self.isCTPUse and self.isAutoAlterPosition:
            codes = self.combinCode()
            try:
                CTP = interface_pyctp(use=True, userkey=self.ctpuser)
                state, orders = CTP.alterPosi(codes)
                if len(orders)- state >0:
                    logger.info(('自动调仓完成', len(orders)- state))
                    Record.insertAll(orders)
            except:
                pass

        logger.info(('总监控币对:', len(self.future_Map), ' 新列表:', num0, ' top10:', num1, ' 未平仓:', len(self.noneUsed)))
        logger.info(([n for n in self.future_Map]))
        logger.info(('暂停币对:', len(self.noneUsed), [n for n in self.noneUsed]))

    def combinCode(self):
        codes = []
        for n in self.future_Map:
            for i in [0, 1]:
                # 暂时禁止交易的品种FU
                if not n[i] in codes and n[i] not in self.banCodeList:
                    codes.append(n[i])
        return codes

    # 按结束时间分割为不同进程
    def seperate(self):
        Base = future_baseInfo()
        maps, codes = {}, []
        dd = str(public.getTime(style='%H:%M:%S'))
        # 按结束时间分组分进程
        for doc in Base.getInfo(self.combinCode()):
            key = doc['nightEnd']
            #
            if '03:00:00' < key < dd: continue

            if key not in maps.keys():
                maps[key] = []
            maps[key].append(doc['code'])

        for key in maps.keys():
            yield maps[key]

    def start(self, full_codes, shareDict, CTP):
        self.shareDict = shareDict
        self.Record = future_orderForm()
        if not self.isWorking:
            self.Record.tablename = self.orderFormTest

        self.Rice = interface_Rice()
        # 基础配置信息类
        self.baseInfo = BaseInfo(full_codes, self.Rice)
        # ctp 接口类
        self.CTP = CTP if CTP is not None else interface_pyctp(use=self.isCTPUse,userkey=self.ctpuser)
        self.CTP.baseInfo = self.baseInfo
        # 进程控制类
        self.procMap = ProcessMap()

        # 设置交易对的收盘时间
        self.Rice.setTimeArea(self.baseInfo.nightEnd)
        # 按k线类型分拆组,进行K线数据调用
        self.groupByKline(full_codes)

        # 初始化节点
        try:
            self.iniNode(full_codes)
        except Exception as e:
            print('iniNode error', e)

        #return
        # 子进程启动
        full_mCodes = self.baseInfo.mainCodes #主力合约
        logger.info(("model_future_detect start: %s " % ",".join(full_mCodes), self.Rice.TimeArea))
        self.Rice.startTick(full_mCodes, callback=self.onTick)

    # 按K线类型分组
    def groupByKline(self, full_codes):
        self.used_future_Map, self.kTypeMap  = [], {}
        for map in self.future_Map:
            if map[0] not in full_codes: continue
            self.used_future_Map.append(map)

            # 按k线时间框类型初始化 kTypeMap dict,
            ktype = int(map[4])
            if ktype not in self.kTypeMap.keys():
                self.kTypeMap[ktype] = []

            for i in [0, 1]:
                mCode = self.baseInfo.mCode(map[i])
                if mCode not in self.kTypeMap[ktype]:
                    self.kTypeMap[ktype].append(mCode)

    # 初始化节点
    def iniNode(self, full_codes):

        openMap = self.Record.getOpenMap(self.methodName, full_codes)
        # 非CTP方式
        if not self.isCTPUse:
            for map in self.used_future_Map:

                key, uid = "_".join(map[0:2]), "_".join(map)
                self.procMap.new(uid)
                if key in openMap:
                    self.procMap.setIni(uid, openMap[key])
                    print(uid, key, self.procMap.isOpen)
            return True

        # 先检查有记录
        ods = []
        for map in self.used_future_Map:
            if  map[0] in self.banCodeList or map[1] in self.banCodeList: continue

            key, uid = "_".join(map[0:2]), "_".join(map)
            self.procMap.new(uid)  # 初始化uid

            if key in openMap:
                docs = self.CTP.iniPosition(map[0:2], openMap[key])
                # 无position的
                if docs is None:
                    print('--- 0 unmatch ---', key)
                    for d in openMap[key]: ods.append(str(d['id']))
                    openMap.pop(key)
                else:
                    print('--1', uid, 'mode', docs[0]["mode"], docs[0]["hands"], docs[1]["hands"])
                    # 满足position,则设置初始状态
                    self.procMap.setIni(uid, docs)  # 有记录的并有匹配position的

        if len(ods) > 0:  # 废弃不满足条件的商品对
            self.Record.disuse(ods)
            pass

        # 无交易记录 ,恢复出交易的
        res = []
        for map in self.used_future_Map:
            key, uid = "_".join(map[0:2]), "_".join(map)
            if key in openMap.keys(): continue

            docs = self.CTP.iniPosition(map[0:2], [])
            if docs is not None:
                # 补充交易记录
                print('--2', uid, 'mode', docs[0]["mode"], docs[0]["hands"], docs[1]["hands"])
                batchid = uuid.uuid1()
                for d in docs:
                    d.update({
                        'batchid': batchid,
                        'uid': uid,
                        'method': self.methodName,
                        'status': 6
                    })
                    res.append(d)
                self.procMap.setIni(uid, docs)  # 有记录的并有匹配position的

        if len(res)> 0: # 添加记录
            # 测试检查
            self.Record.insertAll(res)

        # 处理僵尸
        if self.isDeadCheck:
            self.dead(full_codes)

    # 处理僵尸商品对,直接卖出
    def dead(self, full_codes):
        t, res = self.CTP.orderDead(full_codes)
        if res is not None and t < len(res):
            logger.info(("dead deal success :", len(res), t))
            self.Record.insertAll([d for d in res if d['status']==6])

    # Tick 响应
    def onTick(self, tick):
        # 计算参数
        for map in self.used_future_Map:
            if map[0] in self.banCodeList: continue

            self.uid = self.procMap.setUid(map) # uid
            self.mCodes = [self.baseInfo.mCode(c) for c in self.procMap.codes]  # 当前主力合约代码
            # 挂起项目
            if self.procMap.isOpen == -9 : continue

            kline = self.procMap.kline
            # 按时长读取k线数据
            dfs = self.Rice.getKline(self.kTypeMap[kline], ktype=kline, key=kline)
            try:
                # 计算指标
                param = self.paramCalc(dfs, tick)
                if param is not None and not np.isnan(param["ma"]):
                    # 执行策略,并下单
                    self.orderCheck(tick, param)
            except Exception as e:
                print(traceback.format_exc())

    # 计算布林参数
    def paramCalc(self, dfs, cur):
        # 分钟线
        if dfs is None or len(dfs) == 0: return None

        c0, c1 = cur[self.mCodes[0]], cur[self.mCodes[1]]
        for key in ["asks", "bids", "ask_vols", "bid_vols"]:
            if (c0[key][0] * c1[key][0] == 0): return None

        # 周期和标准差倍数
        period, scale = self.procMap.period, self.procMap.scale
        size =  period + 10

        # 去掉当前的即时k线
        df0, df1 = dfs[self.mCodes[0]][-size:-1], dfs[self.mCodes[1]][-size:-1]

        # 计算相关参数
        close = (df0["close"] / df1["close"])
        # nan 处理
        close = close.fillna(close[close.notnull()].mean())

        # 添加最新
        close = close.append(pd.Series(c0["last"] / c1["last"]))

        ma = ta.MA(close, timeperiod=period)
        sd = ta.STDDEV(close, timeperiod=period, nbdev=1)
        top, lower = ma + scale * sd, ma - scale * sd
        #
        width = (top - lower) / ma * 100
        #

        widthDelta = ta.MA(width - width.shift(1), timeperiod=3)
        # 即时K线取2点中值

        wd2 = widthDelta - widthDelta.shift(1)
        wd2m = widthDelta * widthDelta.shift(1)

        return {
            "ma": ma.values[-1],
            "top": top.values[-1],
            "lower": lower.values[-1],
            "width": width.values[-1],
            "std": sd.values[-1],
            "close": c0["last"] / c1["last"],
            "widthdelta": widthDelta.values[-1],  # 布林带变化
            "wd2": wd2.values[-1],  # 布林带二阶变化率
            "wd2m": wd2m.values[-1],

            "p_l": c0["asks"][0] / c1["bids"][0],  # 买入铜,卖出铅价格
            "p_h": c0["bids"][0] / c1["asks"][0],  # 买入铅,卖出铜价格
            "delta": (c0["asks"][0] / c1["bids"][0] - c0["bids"][0] / c1["asks"][0]) / sd.values[-1],
            "interval":0,
        }

    itemCount = 0
    def debugT(self,str, n=1000):
        self.itemCount += 1
        if self.itemCount % n ==0:
            print(self.itemCount, str)

    def orderCheck(self, cur, param):
        isOpen, isRun, isstop = self.procMap.isOpen, False, 0
        wline, sd2 = self.procMap.widthline, self.procMap.scaleDiff2

        if param["delta"] > self.deltaLimit: return None
        # 开仓
        cond1, cond2 = False, False
        if wline > 0:
            # 布林宽带变化率
            cond1 = (param['widthdelta'] < wline and param['wd2'] < (wline / 2))
            # 拐点
            cond2 = param['wd2m'] < 0

        if isOpen == 0:
            # 已关闭的交易对只平仓, 不再开仓
            if self.procMap.codes in self.noneUsed: return None
            # 大于上线轨迹
            if (param["p_h"] > param["top"]) and cond1:
                isOpen, isRun = -1, True

                # 低于下轨线
            elif (param["p_l"] < param["lower"]) and cond1:
                isOpen, isRun = 1, True


            elif ((param["p_h"] + sd2 * param['std']/2) > param["top"]) and not cond1 and cond2:
                isOpen = -2
                isRun = True

            elif ((param["p_l"] - sd2 * param['std']/2) < param["lower"]) and not cond1 and cond2:
                isOpen = 2
                isRun = True

        # 平仓
        else:

            stopMinutes = self.stopTimeLine * self.procMap.period * self.procMap.kline
            preNode = self.procMap.preNode

            cond3 = (isOpen * ((param['p_h'] if isOpen > 0 else param['p_l']) - param['ma'])) >= 0
            #
            cond4 = (isOpen * (
                    ((param['p_h'] + sd2 / 2 * param['std']) if isOpen > 0 else (
                            param['p_l'] - sd2 / 2 * param['std'])) - param['ma'])) >= 0

            # 回归ma则平仓  或  超过24分钟 或到收盘时间 强制平仓
            if cond4 and not cond1 and cond2:
                isOpen, isRun, isstop = 0, True, 2

            elif cond3 and cond1:
                isOpen, isRun = 0, True

            # 止损
            elif stopMinutes > 0 and preNode is not None:
                tdiff = self.Rice.timeDiff(preNode[0]['createdate'], quick=stopMinutes)
                if tdiff > stopMinutes and cond4 and cond2:
                    isOpen, isstop = 0, 1
                    isRun = True

        #self.debugT((self.uid,isOpen,isRun))

        if isRun:
            self.order(cur, isOpen, param, isstop=isstop)

    def order(self, cur, mode, param, isstop=0):
        # 当前tick对
        n0, n1 = cur[self.mCodes[0]], cur[self.mCodes[1]]

        # future_baseInfo 参数值
        b0, b1 = (self.baseInfo.doc(self.procMap.codes[i]) for i in [0, 1])
        times0, times1 = b0["contract_multiplier"], b1["contract_multiplier"]

        preNode = self.procMap.preNode
        # 每次交易量
        v0 = (round(self.iniAmount / n0["last"] / times0, 0) * times0) if not preNode else preNode[0]["hands"] * times0
        v1 = round(self.iniAmount / n1["last"] / times1, 0) * times1 if not preNode else preNode[1]["hands"] * times1

        # 开仓 1/ 平仓 -1
        isOpen = 0 if mode == 0 else 1

        # 买 / 卖 ,  若mode=0. 则按持仓方向平仓操作
        isBuy = -preNode[0]["mode"] if (mode == 0 and preNode is not None) else mode

        # 费率
        fee0 = (v0 / times0 * b0["ratio"]) if b0["ratio"] > 0.5 else (
                b0["ratio"] * v0 * (n0["asks"][0] if isBuy == 1 else n0["bids"][0]))
        fee1 = (v1 / times1 * b1["ratio"]) if b1["ratio"] > 0.5 else \
            (b1["ratio"] * v1 * (n1["asks"][0] if isBuy == -1 else n1["bids"][0]))

        now = public.getDatetime()
        # 使用uuid作为批次号
        if mode != 0: self.procMap.batchid = uuid.uuid1()

        doc = {
            "createdate": now,
            "code": n0["code"],
            "symbol": self.baseInfo.ctpCode(n0["code"]),
            "price": n0["asks"][0] if isBuy == 1 else n0["bids"][0],
            "vol": v0,
            "hands": v0 / times0,
            "ini_hands": v0 / times0,  # 提交单数
            "ini_price": n0["asks"][0] if isBuy == 1 else n0["bids"][0],  # 提交价格
            "mode": isBuy,
            "isopen": isOpen,
            "isstop":isstop,
            "fee": fee0,
            "income": 0,
            "rel_price": param["p_l"] if isBuy == 1 else param["p_h"],
            "rel_std": param["std"],
            "batchid": self.procMap.batchid,
            "delta": param["delta"],
            "bullwidth": param["width"],
            "widthdelta": param["widthdelta"],
            "status": 0,  # 定单状态
            "method": self.methodName,
            "uid": self.uid
        }

        doc1 = copy.deepcopy(doc)
        doc1.update({
            "code": n1["code"],
            "symbol": self.baseInfo.ctpCode(n1["code"]),
            "price": n1["asks"][0] if isBuy == -1 else n1["bids"][0],
            "vol": v1,
            "ini_price": n1["asks"][0] if isBuy == -1 else n1["bids"][0],
            "hands": v1 / times1,
            "ini_hands": v1 / times1,
            "mode": -isBuy,
            "fee": fee1,
        })

        if mode == 0 and preNode is not None:
            p0, p1 = preNode[0], preNode[1]
            doc["income"] = round(p0["mode"] * (doc["price"] - p0["price"]) * p0["vol"] - doc["fee"], 2)
            doc1["income"] = round(p1["mode"] * (doc1["price"] - p1["price"]) * p1["vol"] - doc1["fee"], 2)
            doc["interval"] = doc1["interval"] = self.Rice.timeDiff(p0['createdate'])
        else:
            doc["income"] = -doc["fee"]
            doc1["income"] = -doc1["fee"]

        # 下单并记录
        self.record([doc, doc1], mode)

    def record(self, orders, mode):
        state = 0
        isOpen = 0 if mode == 0 else 1
        # 发送订单并记录到数据库
        if self.isCTPUse and self.CTP is not None:
            # 检查订单条件
            state = self.CTP.checkPosition(orders, isOpen)
            if state == 0:
                # 发送订单
                try:
                    self.CTP.sendOrder(orders)
                    # 检查全部执行结果
                    state, orders = self.CTP.checkResult()
                except Exception as e:
                    print(traceback.format_exc())
                    state = 2

        if state == 0:
            logger.info(["---- purchase record:-- ", state, self.uid, mode])
            # 保存 到进程变量
            self.procMap.preNode = orders if (mode != 0) else None
            self.procMap.isOpen = mode
            # 交易成功
            self.Record.insertAll(orders)

        elif state < 0:
             print('----账户持仓检查不符合 ----:', state, self.uid, mode, orders)
             time.sleep(3)

        elif state == 1:
             logger.info(('---- 配对只成交一单--:', state, self.uid, mode, orders))
             self.procMap.isOpen = -9 # 标记为挂起项目
             # 执行反向操作
             s, res = self.CTP.forceOrder(orders)
             if s==0:
                 logger.info(('--配对单成交反向操作成功----:', res))
                 orders.extend(res)   # 添加反向操作记录

             self.Record.insertAll(orders)
             time.sleep(3)
        else:
             print('---- 交易不成功 ----:', state, self.uid, mode, orders)
             time.sleep(3)
예제 #2
0
class data_future_Rice(object):
    # 更新夜盘收盘时间和最新价格
    sql_nightEnd = """
        update future_baseInfo 
        set lastPrice = %s,
            lastVolume = %s
        where code = '%s' 
    """

    # 更新夜盘收盘时间和最新价格
    sql_width15 = """
        update future_baseInfo 
        set width15 = %s, slope=%s, range = %s , atr=%s 
        where code = '%s' 
        """

    ch_index = ['零', '一', '二', '三', '四', '五', '三特', '无']
    trend_index = ['无', '多', '空']

    def __init__(self):
        self.indexCodeList = [('IH', '000016.XSHG'), ('IF', '399300.XSHE'),
                              ('IC', '399905.XSHE')]

        mZhao = model_future_zhao_v1()
        self.banCodeList = mZhao.banCodeList  # 暂时不操作的code(不列交易量低的)
        self.longCodeList = mZhao.longCodeList  # 只做多仓的list
        self.shortCodeList = mZhao.shortCodeList  # 只做空仓的list

        self.oneCodeList = ['SC', 'IH', 'IF', 'IC']  # 最低为1手单的
        self.columns_posiDetail = [
            'InstrumentID', 'Direction', 'OpenPrice', 'Volume',
            'CloseProfitByTrade', 'PositionProfitByTrade', 'ExchangeID',
            'OpenDate'
        ]
        #
    def getAllMain(self):
        Rice = interface_Rice()
        codes = Rice.allFuture(isSave=True)
        print(codes)

    def k_fix(self, row, mode):
        close, open, high, low = (row[key]
                                  for key in ['close', 'open', 'high', 'low'])
        d0 = abs(close - open) / open
        lim, rate = 0.003, 0.075
        if mode == 1:
            if close > open and open != 0:
                trend = 1 if high == open else abs(close - open) / (high -
                                                                    open)
                opt = (d0 < lim and trend < rate) or (d0 > lim
                                                      and trend < rate * 2)
                return close if opt else high
            else:
                return high

        elif mode == -1:
            if close < open and open != 0:
                trend = 1 if low == open else abs(open - close) / (open - low)
                opt = (d0 < lim and trend < rate) or (d0 > lim
                                                      and trend < rate * 2)
                return close if opt else low
            else:
                return low

    # 买入后的最高/最低价
    def getMax(self, df0, s, e, mode):
        s = str(s)[:10]
        if mode > 0:
            ss = df0[(df0['datetime'] >= s) & (df0['datetime'] <= e)]
            mm = ss.ix[:-1, 'close'].max()
            if np.isnan(mm): print(s, e, ss)

            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] <= e)].ix[:-1, 'close'].max()
        else:
            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] <= e)].ix[:-1, 'close'].min()

    def isout0(self, row):
        close, ma20, ma55 = (row[key] for key in "close,ma20,ma55".split(","))
        return 0 if np.isnan(ma55) else 1 if close > ma55 else -1

    def isout(self, row, pos):
        close, ma20, ma55, trend = (
            row[key] for key in "close,ma20,ma55,trend".split(","))
        pt = pos if pos != 0 else trend if trend != 0 else 1 if ma20 < ma55 else -1
        return 1 if close > ma55 and pt > 0 else -1 if close < ma55 and pt < 0 else 0

    def isMam(self, row):
        #
        mad, mac, mac2, mac3 = (row[key]
                                for key in "mad,mac,mac2,mac3".split(","))
        opt = np.isnan(mad) or mad > 0 or mac == 0
        # 为零时同向偏转
        opt1 = (mad == 0
                and (mac * mac2 > 0 or (mac2 == 0 and mac * mac3) > 0))
        return 0 if (opt or opt1) else 1 if mac > 0 else -1

    # 每日自动计算ATR和最新
    def autoCreateAtr(self, type=0):
        Rice = interface_Rice()
        Rice.setIndexList(self.indexCodeList)
        Base = future_baseInfo()
        Record = self.Record = future_orderForm()
        Model = model_future_zhao_v1()

        methods = ['mZhao', 'mZhao55']
        self.iniAmount, self.stopLine = 15400000, 0.0025
        if type == 1:
            methods = ['zhao', 'zhao55']
            self.iniAmount, self.stopLine = 20000000, 0.0025

        codes = Base.getUsedMap(hasIndex=True)
        BI = BaseInfo(codes)
        mCodes = Rice.getMain(codes)
        #print(codes)

        end = None
        dd = str(public.getTime(style='%H:%M:%S'))
        valids = Rice.getValidDate(start=-15, end=0)

        if ('18:15:00' < dd < '23:59:59'):
            end = public.getDate(diff=0)
        else:
            end = str(valids[-2])

        dfs = Rice.kline(mCodes,
                         period='1d',
                         start=public.getDate(diff=-150),
                         end=end,
                         pre=20)
        docs = []

        Tmap = Record.trendMap(methods)

        Pos = []
        j = 0
        for m in methods:
            Pos.append(Record.getOpenMap(method=m, batchNum=1))

        for mcode in mCodes:
            code = BI.parseCode(mcode)
            if code in self.banCodeList: continue

            df = dfs[mcode]

            close = df['close']
            df["datetime"] = df.index

            df["ma10"] = ma10 = ta.MA(close, timeperiod=10)
            df["ma20"] = ma20 = ta.MA(close, timeperiod=20)
            df["ma55"] = ta.MA(close, timeperiod=55)

            atr21 = ta.ATR(df['high'], df['low'], close, timeperiod=21)
            df['3atr'] = atr21 * 3

            # 计算ma10-ma20 穿越线间距
            df['mac'] = mac = ma10 - ma20
            df['mac2'] = mac.shift(2)
            df['mac3'] = mac.shift(3)

            # isPoint
            df['mad'] = mac * mac.shift(1)
            df['mam'] = mam = df.apply(lambda row: self.isMam(row), axis=1)
            minidx, maxidx = ta.MINMAXINDEX(mam, timeperiod=75)
            df['interval'] = abs(minidx - maxidx)

            # 修正不正常K线
            df['high'] = df.apply(lambda row: self.k_fix(row, 1), axis=1)
            df['low'] = df.apply(lambda row: self.k_fix(row, -1), axis=1)

            # 唐奇安线18日
            df['tu_s'] = ta.MAX(df['high'], timeperiod=18 - 1)
            df['td_s'] = ta.MIN(df['low'], timeperiod=18 - 1)

            # 唐奇安线27日
            df['tu_s1'] = ta.MAX(df['high'], timeperiod=27 - 1)
            df['td_s1'] = ta.MIN(df['low'], timeperiod=27 - 1)

            # 唐奇安线34日
            df['tu_34'] = ta.MAX(df['high'], timeperiod=33)
            df['td_34'] = ta.MIN(df['low'], timeperiod=33)

            # 40日低点
            ld = close[close.notnull()]
            p = 40 if len(ld) > 40 else len(ld) - 1
            df['tu_d'] = ta.MAX(df['high'], timeperiod=p - 1)
            df['td_d'] = ta.MIN(df['low'], timeperiod=p - 1)

            fp, fd = 27, 5

            # 计算穿越值
            out = df.apply(lambda row: self.isout0(row), axis=1)
            df['out_s'] = ta.SUM(out, timeperiod=fp)
            df['trend'] = df['out_s'].apply(lambda x: -1 if x > fd else 1
                                            if x < -fd else 0)

            #posTrend = 0 if code not in trendMap else trendMap[code]['trend']
            df['isout'] = isout = df.apply(lambda row: self.isout(row, 0),
                                           axis=1)
            df['isout3'] = ta.SUM(isout, timeperiod=3)
            df['isout5'] = ta.SUM(isout, timeperiod=5)

            param = copy.deepcopy(df.iloc[-1]).to_dict()
            isLong, type = 1, 0
            if code in Tmap:
                isLong = Tmap[code]['trend']
                type = 1
            elif param['trend'] != 0:
                isLong = param['trend']
                type = 2
            else:
                isLong = -1 if param['ma20'] > param['ma55'] else 1
                type = 3

            j += 1
            isL = -1 if code in self.shortCodeList else 1 if code in self.longCodeList else 0

            if code in []:
                print(code, isLong, isL, param['trend'])
                file = Rice.basePath + '%s_%s_%s.csv' % (
                    code, public.getDatetime(style='%Y%m%d_%H%M%S'),
                    methods[0])
                df.to_csv(file, index=0)

            # 计算交易手数
            mul = BI.att(code, "contract_multiplier")
            dp = param['td_d'] if isLong > 0 else param['tu_d']
            p18 = param['tu_s'] if isLong > 0 else param['td_s']
            p27 = param['tu_s1'] if isLong > 0 else param['td_s1']

            if np.isnan(param['ma55']) or np.isnan(p18):
                print('period no long:', code)
                continue

            ma20v_18 = (self.iniAmount * self.stopLine / abs(p18 - dp) / mul)
            ma20v_18 = int(ma20v_18 + 0.2)

            ma20v_27 = (self.iniAmount * self.stopLine / abs(p27 - dp) / mul)

            ma20v_27 = int(ma20v_27 + 0.2)
            #
            ma55v = (self.iniAmount * self.stopLine / param['3atr'] / mul)
            ma55v = int(ma55v + 0.2)

            # 固定一手交易
            if code in self.oneCodeList:
                ma55v = ma20v_18 = ma20v_27 = 1

            # 计算持仓和止损
            p = np.zeros((2, 3))
            i = 0
            mp = 0

            for pos in Pos:
                if code in pos:
                    d = pos[code][0]

                    # 最近高点
                    sign = np.sign(int(d['mode']))
                    p[i][0] = sign * d['hands']
                    p[i][2] = mul * d['hands'] * (param['close'] -
                                                  d['price']) * sign

                    if i == 0:
                        p[i][1] = param['td_d'] if sign > 0 else param['tu_d']
                    else:
                        mp = self.getMax(df, d['createdate'],
                                         public.getDate(diff=1), d['mode'])
                        if np.isnan(mp):
                            print('no max Price:', code, mp)

                        p[i][1] = round(mp, 1) - sign * round(param['3atr'], 1)
                i += 1

            param.update({
                'code': mcode,
                '方向': '多' if isLong == 1 else '空',
                'price_18': p18,
                'vol_18': ma20v_18,
                'price_27': p27,
                'vol_27': ma20v_27,
                'vol_55': ma55v,
                '乘数': mul,
                '3ATR': round(param['3atr'], 1),
                '系统1持仓': p[0][0],
                'price_40': dp,
                '40日止损价': p[0][1],
                '浮盈1': p[0][2],
                '系统2持仓': p[1][0],
                '最高点': mp,
                '3ATR止损价': p[1][1],
                '浮盈2': p[1][2],
                '状态': Model.getStatus(methods, code),
                '指定方向': Model.getTrend(code),
            })
            docs.append(param)

        res = pd.DataFrame(docs,
                           columns=[
                               'code', 'close', '方向', 'price_40', 'price_18',
                               'vol_18', 'price_27', 'vol_27', '3ATR',
                               'vol_55', '乘数', '系统1持仓', '40日止损价', '浮盈1',
                               '系统2持仓', '最高点', '3ATR止损价', '浮盈2', '状态', '指定方向'
                           ])

        res = res.sort_values('code', ascending=True)
        file = Rice.basePath + 'future_%s_%s.csv' % (public.getDate(),
                                                     methods[0])
        res.to_csv(file, index=0)
        logger.info(('autoCreateAtr finished:', len(docs)))
        return res

    def getStatus(self, methods, code):
        posMode = self.Record.openMode(methods, code)
        lastStop = self.Record.lastStop(methods, code)
        trend = self.getTrend(code)

        status = -1
        if posMode[1] == 0:
            if lastStop[0] == 6 or (lastStop[0] == 0 and trend == 0):
                status = 0

            elif lastStop[0] in [3, 5] or (lastStop[0] == 0 and trend != 0):
                status = 1

            elif lastStop[0] == 2:
                status = 2

        elif posMode[1] == 1:
            if posMode[0].find('55') > -1:
                status = 5

            elif lastStop[0] == 3:
                status = 3.5

            else:
                status = 3

        elif posMode[1] == 2:
            status = 4

        return status

    def getTrend(self, code):
        return 1 if code in self.longCodeList else -1 if code in self.shortCodeList else 0

    def getMaps(self):
        orderMap, codes, mCodes = {}, [], []
        b = BaseInfo([])
        obj = interface_pyctp(baseInfo=b, userkey='zhao')
        res = obj.qryPositionDetail()
        methodName = 'mZhao'
        codes55 = ['J1905', 'Y1905', 'P1905', 'NI1905', 'HC1905']
        for r in res:
            if r['Volume'] > 0:
                s = r['InstrumentID'].decode('gbk')
                if s not in orderMap:
                    m = b.parseMCode(s)
                    c = b.parseCode(m)
                    order = {
                        "symbol":
                        s,
                        "code":
                        m,
                        "mode":
                        1 if r['Direction'].decode('gbk') == '0' else -1,
                        "isopen":
                        1,
                        "hands":
                        r['Volume'],
                        "price":
                        r['OpenPrice'],
                        "method":
                        methodName,
                        "createdate":
                        public.parseTime(r['OpenDate'].decode('utf-8'),
                                         format='%Y%m%d',
                                         style='%Y-%m-%d %H:%M:%S')
                    }
                    orderMap[s] = order
                else:
                    orderMap[s]["hands"] += r['Volume']

        orders = []
        for key in orderMap.keys():
            doc = orderMap[key]
            if doc['code'] in codes55:
                v = doc['hands']
                v0 = int(v / 2)
                doc['hands'] = v0
                orders.append(doc)

                # method55
                v1 = v - v0
                doc1 = copy.deepcopy(doc)
                doc1['hands'] = v1
                doc1['method'] = 'mZhao55'
                orders.append(doc1)
            else:
                orders.append(doc)
        return orders

    def getMaps2(self, mapList):
        codes = [c[0] for c in mapList]
        orders = []
        mCodes = self.Rice.getMain(codes)
        snaps = self.Rice.snap(mCodes)
        i = 0
        for m in mCodes:
            s = self.BI.ctpCode(m)
            order = {
                "symbol": s,
                "code": m,
                "name": mapList[i][0],
                "mode": mapList[i][1],
                "isopen": mapList[i][2],
                "hands": mapList[i][3],
                "price":
                snaps[m]['last'] if len(mapList[i]) < 6 else mapList[i][5],
                "method": mapList[i][4],
                "createdate": public.getDatetime(diff=0),
            }
            orders.append(order)
            i += 1
        return orders

    # 平仓
    def closeFuture(self, id='278231', price=5059, isstop=2, date=None):
        self.Record = future_orderForm()
        self.BI = BaseInfo([])

        doc = self.Record.getById(id)
        docnew = copy.deepcopy(doc)
        base = self.BI.doc(doc['name'])
        amount = price * doc['hands'] * base['contract_multiplier']
        r = base['ratio']
        fee = doc['hands'] * r if r >= 0.5 else amount * r
        docnew.update({
            "isopen":
            0,
            "isstop":
            isstop,
            "price":
            price,
            "mode":
            -doc["mode"],
            "vol":
            doc['hands'] * base['contract_multiplier'],
            "status":
            6,
            "fee":
            fee,
            "createdate":
            public.getDatetime() if date is None else date,
            "income":
            np.sign(doc["mode"]) * (price - doc['price']) * doc['hands'] *
            base['contract_multiplier'] - fee,
            "memo":
            ''
        })
        print(docnew)
        self.Record.insert(docnew)

        # 平仓

    def newFuture(self,
                  id='278231',
                  price=5059,
                  mode=2,
                  hands=5,
                  date=None,
                  test=False,
                  new_method=None,
                  mcode=None,
                  memo=''):

        self.Record = future_orderForm()
        self.BI = BaseInfo([])

        doc = self.Record.getById(id)
        docnew = copy.deepcopy(doc)

        base = self.BI.doc(doc['name'])

        amount = price * hands * base['contract_multiplier']
        r = base['ratio'] * 1.1

        fee = hands * r if r >= 0.5 else amount * r

        del docnew['id']
        name = doc['name']

        # 替换method
        if new_method is None:
            mode_old = doc['mode']
            uid, method = doc['uid'], doc['method']
            m0 = method[:-2] if method.find('55') != -1 else method + '55'
            print(mode_old, uid, m0)
            if (abs(mode_old) < 5 and abs(mode) > 4) or (abs(mode_old) > 4
                                                         and abs(mode) < 5):
                uid = uid.replace(method, m0)
                method = method.replace(method, m0)

        else:
            uid, method = doc['uid'], doc['method']
            uid = uid.replace(method, new_method)
            method = new_method

        docnew.update({
            "code": self.BI.mCode(name) if mcode is None else mcode,
            "symbol": self.BI.ctpCode(name),
            "isopen": 1,
            "isstop": 0,
            "price": price,
            "mode": mode,
            "hands": hands,
            "ini_hands": hands,
            "ini_price": price,
            "vol": hands * base['contract_multiplier'],
            "status": 6,
            "fee": round(fee, 2),
            "batchid": str(uuid.uuid1()),
            "createdate": public.getDatetime() if date is None else date,
            "income": round(-fee, 2),
            "method": method,
            "uid": uid,
            "memo": memo
        })
        print(docnew)
        if not test:
            self.Record.insert(docnew)

    def alterFuture(self, id='278231', price0=0, price1=0, mCode=None):
        # 平仓
        self.closeFuture(id=id, price=price0, isstop=4)
        # 开仓
        Rice = interface_Rice()
        doc = self.Record.getById(id)
        docnew = copy.deepcopy(doc)

        if mCode is None:
            m = Rice.getMain([doc['name']])[0]
        else:
            m = mCode

        docnew.update({
            "price": price1,
            "ini_price": price1,
            "code": m,
            "symbol": self.BI.parseCtpCode(m),
            "status": 6,
            #"createdate": str(doc['createdate']),
            "batchid": str(uuid.uuid1())
        })
        print(docnew)
        self.Record.insert(docnew)

    def orderStart(self):
        self.BI = BaseInfo([])
        self.Rice = interface_Rice()
        self.Record = future_orderForm()
        self.Record.tablename = 'future_orderForm_1'
        self.Rice.setIndexList([('IH', '000016.XSHG'), ('IF', '399300.XSHE'),
                                ('IC', '399905.XSHE')])

        map = [
            ['AP', 1, 1, 5, 'mZhao', 11087],
            #['IH', 1, 1, 1, 'mZhao55']
        ]
        orderMap = self.getMaps2(map)
        self.addOrder(orderMap)

    #
    def addOrder(self, orderMap):
        res = []
        for order in orderMap:
            m = order['code']
            dfs = self.Rice.kline([m],
                                  period='1d',
                                  start=public.getDate(diff=-100),
                                  pre=10)
            df0 = dfs[m]

            # 计算40天最小值
            df0['high'] = df0.apply(lambda row: self.k_fix(row, 1), axis=1)
            df0['low'] = df0.apply(lambda row: self.k_fix(row, -1), axis=1)
            period = 40 if len(df0) >= 40 else len(df0)
            print(m, period)
            mx = ta.MAX(df0['high'], timeperiod=period).values[-1]
            mi = ta.MIN(df0['low'], timeperiod=period).values[-1]
            dp = mx if order['mode'] < 0 else mi

            ra, mul = self.BI.att(m, 'ratio'), self.BI.att(
                m, 'contract_multiplier')

            fee0 = (order['hands'] *
                    ra) if ra > 0.5 else (mul * order['hands'] *
                                          order['price'] * ra)
            doc = copy.deepcopy(order)
            doc.update({
                "vol":
                order['hands'] * mul,
                "fee":
                fee0,
                "ini_hands":
                order['hands'],  # 提交单数
                "ini_price":
                order['price'],  # 提交价格
                "isstop":
                0,
                "income":
                -fee0,
                'stop_price':
                dp,
                "batchid":
                uuid.uuid1(),
                "status":
                6,  # 定单P执行CT返回状态
                "uid":
                '%s_40_2.0_1_0_%s' % (self.BI.parseCode(m), order['method'])
            })

            res.append(doc)

        self.Record.insertAll(res)

    def getMonTick(self, codes=None, method='dema5', num=4000):
        Tick = mon_tick()
        Rice = interface_Rice()
        if codes is None: codes = ['MA', 'A']
        diff = -1
        for c in codes:
            docs = Tick.getTick(c, count=num, method=method)
            print(c, len(docs))
            if len(docs) > 0:
                f = Rice.basePath + "%s_%s.csv" % (c, public.getDate())
                r = [d for d in docs]
                r.reverse()
                df = pd.DataFrame(r)
                df.drop(['_id'], axis=1, inplace=True)
                try:
                    df.to_csv(f, index=0)
                    print("%s  output" % f)
                except:
                    continue

    def getDf(self, codes, period='1d'):
        Rice = interface_Rice()
        Rice.setIndexList(self.indexCodeList)
        Base = future_baseInfo()
        BI = BaseInfo([])
        if len(codes) == 0:
            codes = Base.getUsedMap(hasIndex=True)

        mCodes = Rice.getMain(codes)
        dfs = Rice.kline(mCodes,
                         period=period,
                         start=public.getDate(diff=-10),
                         pre=200)
        i = 0

        for mcode in mCodes:
            c = codes[i]
            last = BI.att(c, 'nightEnd')[0:6].replace(':', '')
            file = Rice.basePath + 'future_%s_%s_%s.csv' % (
                mcode, last, public.getDatetime(style='%Y%m%d_%H%M%S'))
            print(mcode, last)
            df = dfs[mcode]
            df['datetime'] = df.index

            df0 = df[df['datetime'] > '2019-01-17 13:47:40.000']
            print(df0.index, len(df0))

            #df.to_csv(file, index=0)
            i += 1
            break

    def compare(self, type=''):

        if type == 'm':
            user = '******'
            methods = ['mZhao', 'mZhao55']
        else:
            user = '******'
            methods = ['zhao', 'zhao55']

        b = BaseInfo([])
        Ctp = interface_pyctp(baseInfo=b, userkey=user)
        map = Ctp.posMap

        Rice = interface_Rice()
        Orders = future_orderForm()
        posMap = {}

        for pos in Orders.posByCode(methods):
            posMap[pos[0]] = pos[1]

            if pos[0] in map and pos[1] == map[pos[0]][0]:
                print('match ', pos, map[pos[0]])
            else:
                if pos[0] in map:
                    print('unmatch ', pos, map[pos[0]])
                else:
                    print('no purchase', pos)

            # 检查是否调仓
            pCode, name = pos[2], pos[0].split("_")[0]
            mCode = Rice.getMain([name])[0]
            if pCode != mCode:
                print(' --------- Need alter position:', pCode, mCode)

        for key in map:
            if len(key) < 6 and key not in posMap:
                print('no record', key, map[key])

        print(len(posMap.keys()))
예제 #3
0
class model_future_ctp(object):
    def __init__(self):
        # 统一参数
        self.iniAmount = 150000  # 单边50万

        self.isWorking = False  # 是否正式运行
        self.isAutoAlterPosition = True
        self.banCodeList = []  # 暂时无权限操作的code
        self.isTickSave = True
        self.batchNum = 1  # 批处理的交易数量
        self.topUse = True  # 启用定时统计列表
        self.timeInterval = 0.5  # 间隔处理时间

        self.indexCodeList = []  # 指数期货

        self.isCTPUse = False  # 是否启用CTP接口(并区分
        self.isDeadCheck = False  # 是否启用自动检查并交易沉淀品种
        self.topFilter = """(count>10)"""
        self.ctpuser = '******'
        self.tickIntList = ['kdjm', 'sarm', 'isout', 'isout3', 'isout5']
        self.tickInterval = 10  # 间隔处理时间

        self.sameLimit = 1  # 同一code允许出现次数
        self.topNumbers = 30  # 最大新币对 (监控币对还包括历史10和未平仓对)
        self.bestTopNumbers = 10
        self.minRate = 0.02  # 最低收益率
        self.orderFormTest = 'future_orderForm_test'
        self.topTableName = 'train_total_dema5'

        self.methodName = 'single'  # 策略名称
        self.relativeMethods = ['mZhao', 'mZhao55']
        self.scaleDiff2 = 0.8
        self.powline = 0.25

        self.widthTimesPeriod = 3
        self.sourceType = 'combin'
        #
        self.future_Map = []
        self.noneUsed = []  # 不再继续的商品对

    def pool(self):
        pool = Pool(processes=6)
        shareDict = Manager().list([])
        CTP = None

        # 初始化codes列表
        if self.topUse:
            self.filterCodes()

        pid = 0
        for codes in self.seperate():
            print('pool send:', pid, len(codes))
            #self.start(codes, shareDict, CTP)
            try:
                pool.apply_async(self.start, (codes, shareDict, CTP))
                time.sleep(3)
                pid += 1
                pass
            except Exception as e:
                print(e)
                continue

        pool.close()
        pool.join()

    def setAlterIncome(self, orders, openDocs):
        for doc in orders:
            c = doc['name']
            if doc['isopen'] == 0 and c in openDocs:
                p0 = openDocs[c][0]
                sign = np.sign(p0['mode'])
                doc["income"] = round(
                    sign * (doc["price"] - p0["price"]) * p0["vol"] -
                    doc["fee"], 2)
                doc["interval"] = self.Rice.timeDiff(p0['createdate'])  # 间隔时间

        return orders

    # 调仓处理
    def alterPosition(self, Record, openCodes):
        # 开盘时CTP调仓处理
        Rice = interface_Rice()
        if self.isCTPUse and self.isAutoAlterPosition:
            openDocs = Record.getOpenMap(self.methodName,
                                         codes=[],
                                         batchNum=self.batchNum)
            try:
                CTP = interface_pyctp(use=True, userkey=self.ctpuser)
                state, orders = CTP.alterPosi(openDocs)

                if len(orders) - state > 0:
                    logger.info(('自动调仓完成', len(orders) - state))
                    orders = self.setAlterIncome(orders, openCodes)
                    Record.insertAll(orders)

            except:
                logger.info(('alterPosition error:', self.methodName))

        elif self.isAutoAlterPosition:
            # 非CTP调仓
            if openCodes is not None:
                openDocs = Record.getOpenMap(self.methodName,
                                             codes=[],
                                             batchNum=self.batchNum)
                orders, d0, d1 = [], {}, {}

                for key in openDocs:
                    # 查询最新主力代码
                    doc, pCode = openDocs[key][0], openDocs[key][0]['code']
                    mCode = Rice.getMain([key])[0]

                    if mCode != pCode:
                        print('start:', pCode, mCode)

                        # 查询最新价格,调仓前和调仓后
                        s = Rice.snap([pCode, mCode])
                        if s is None: continue
                        price0 = s[pCode]['bids'][0] if doc['mode'] > 0 else s[
                            pCode]['asks'][0]
                        price1 = s[mCode]['bids'][0] if doc['mode'] < 0 else s[
                            mCode]['asks'][0]

                        d0 = copy.deepcopy(doc)
                        d0['mode'] = -doc['mode']
                        d0['isopen'] = 0
                        d0['price'] = d0['rel_price'] = price0
                        sign = np.sign(-d0["mode"])
                        d0["income"] = round(
                            sign * (price0 - doc["price"]) * d0["vol"] -
                            doc["fee"], 2)
                        del d0['id']

                        # 按原状态买入
                        d1 = copy.deepcopy(doc)
                        d1['code'] = mCode
                        d1['status'] = d0['status'] = 4

                        d0['method'] = d1['method'] = self.methodName
                        d1['rel_price'] = d1['price'] = price1
                        d0['createdate'] = d1[
                            'createdate'] = public.getDatetime()
                        d1['batchid'] = uuid.uuid1()
                        del d1['id']

                        orders.append(d0)
                        orders.append(d1)
                        logger.info(('自动调仓完成:', doc['code'], mCode, 4))

                if len(orders) > 0:
                    Record.insertAll(orders)
                    pass

    def combinCode(self):
        codes = []
        for n in self.future_Map:
            if not n[0] in codes and n[0] not in self.banCodeList:
                codes.append(n[0])
        return codes

    # 按结束时间分割为不同进程
    def seperate(self):
        Base = future_baseInfo()
        maps, codes = {}, []
        dd = str(public.getTime(style='%H:%M:%S'))

        # 按结束时间分组分进程
        for doc in Base.getInfo(self.combinCode()):
            key = key0 = doc['nightEnd']
            if '03:00:00' < key0 < dd: continue
            if '08:30:00' < dd < '15:00:00':
                key = '15:00:00' if '09:00:00' < key0 < '15:30:00' else '23:30:00' if '15:30:00' < key0 < '23:35:00' else '02:30:00'
                pass

            if key not in maps.keys():
                maps[key] = []

            maps[key].append(doc['code'])

        pc = 11
        for key in maps.keys():
            if len(maps[key]) < pc + 1:
                yield maps[key]
            else:
                l, t = len(maps[key]), len(maps[key]) // pc
                for i in range(t + 1):
                    s, e = i * pc, l if (i + 1) * pc > l else (i + 1) * pc
                    if s < e:
                        yield maps[key][s:e]

    def start(self, full_codes, Rice=None, CTP=None):
        # print(full_codes)
        self.Record = future_orderForm()
        self.PStatus = future_status()

        if not self.isWorking: self.Record.tablename = self.orderFormTest

        if self.isTickSave:
            self.Tick = mon_tick()

        self.Rice = interface_Rice() if Rice is None else Rice

        # 基础配置信息类
        self.baseInfo = BaseInfo(full_codes, self.Rice)

        # ctp 接口类
        self.CTP = interface_pyctp(
            use=self.isCTPUse, userkey=self.ctpuser) if CTP is None else CTP
        self.CTP.baseInfo = self.baseInfo

        # 进程控制类
        self.procMap = ProcessMap()

        # 趋势预测
        self.trendMap = self.Record.trendMap(self.relativeMethods)

        # 指数期货
        self.indexList = [c[0] for c in self.indexCodeList]

        # 设置交易对的收盘时间
        self.Rice.setTimeArea(self.baseInfo.nightEnd)

        if len(self.indexCodeList) > 0:
            self.Rice.setIndexList(self.indexCodeList)

        # 按k线类型分拆组,进行K线数据调用
        self.groupByKline(full_codes)

        # 初始化节点
        self.iniNode(full_codes)

        # 子进程启动
        full_mCodes = self.baseInfo.mainCodes  # 主力合约

        logger.info(("model_future_detect start: %s " % ",".join(full_codes),
                     self.Rice.TimeArea))

        self.Rice.startTick(full_mCodes,
                            kmap=self.kTypeMap,
                            timesleep=self.timeInterval,
                            source=self.sourceType,
                            callback=self.onTick)

    # 按K线类型分组
    def groupByKline(self, full_codes):
        self.used_future_Map, self.kTypeMap = [], {}

        for map in self.future_Map:
            if map[0] not in full_codes: continue
            self.used_future_Map.append(map)

            # 按k线时间框类型初始化 kTypeMap dict,
            ktype = int(map[3])
            # 字典
            self.kTypeMap[map[0]] = ktype
            # 分组
            if ktype not in self.kTypeMap.keys():
                self.kTypeMap[ktype] = []

            mCode = self.baseInfo.mCode(map[0])
            if mCode not in self.kTypeMap[ktype]:
                self.kTypeMap[ktype].append(mCode)

    # 初始化节点
    def iniNode(self, full_codes):
        openMap = self.Record.getOpenMap(self.methodName,
                                         codes=full_codes,
                                         batchNum=self.batchNum)
        statusMap = self.PStatus.getStatus(self.topTableName)

        # 非CTP方式
        for map in self.used_future_Map:
            #print(map)
            key, uid = map[0], "_".join(map)
            self.procMap.new(uid)  # 初始化进程参数类

            # 初始化品种状态
            if key in openMap:
                found = True
                # CTP方式检查
                if self.isCTPUse:
                    # 检查持仓满足
                    found = self.CTP.checkPosition(openMap[key],
                                                   0,
                                                   reverse=-1,
                                                   refresh=False) == 0
                    #if key =='IH': print(openMap[key], found, res)

                if found:
                    status = statusMap[key] if key in statusMap else 0
                    self.procMap.setIni(uid, openMap[key], status=status)
                    logger.info(
                        (uid, key, self.procMap.isOpen, self.procMap.status))

    pointColumns = ['wdd', 'pow', 'powm', 'trend', 'isout']

    def orderCheck(self, cur, param):
        pass

    def paramCalc(self, dfs, cur):
        pass

    def sd(self, x):
        s = round(x * 1.6, 0) / 10
        return np.sign(s) * 0.8 - 0.1 if abs(s) > 0.8 else s - 0.1

    def stand(self, ser):
        ser = ser.fillna(0)
        return ser / ser.abs().mean()

    def turn(self, mm, md, mode):
        return 0 if mm > 0 else 1 if mode * md > 0 else -1

    def apart(self, PS, ktype):
        apart = math.pow(
            (int(time.time()) % (60 * ktype)) * 1.0 / (60 * ktype), 0.5)
        return PS * apart + PS.shift(1) * (1 - apart)

    itemCount = 0
    cvsMap, cvsCodes = {}, []

    def debugT(self, str, n=1000, param=None):
        self.itemCount += 1
        if str != '' and self.itemCount % n == 0:
            logger.info((self.itemCount, str))

        #print(self.isTickSave)

        if not self.isTickSave: return

        code, method = self.procMap.codes[0], self.procMap.currentUid.split(
            "_")[-1]
        #print(self.csvCodes)
        if param is not None and (code in self.cvsCodes
                                  or self.cvsCodes == []):
            # param = param.to_dict()
            param['code'] = code
            param['method'] = method
            param['isopen'] = self.procMap.isOpen
            param['status'] = self.procMap.status

            for key in self.tickIntList:
                if key in param: param[key] = int(param[key])

            # 初始化
            if code not in self.cvsMap:
                self.cvsMap[code] = [param]
                self.cvsMap['c_' + code] = 1

            else:
                self.cvsMap['c_' + code] += 1
                c, t = self.cvsMap[code], self.cvsMap['c_' + code]

                if len(c) > 2:
                    if self.isTickSave:
                        self.Tick.col.insert_many(self.cvsMap[code])

                    self.cvsMap[code] = []

                elif t % self.tickInterval == 0:
                    #print(param)
                    self.cvsMap[code].append(param)

    def debugR(self, param=None):

        if not self.isTickSave: return
        code, method = self.procMap.codes[0], self.procMap.currentUid.split(
            "_")[-1]
        if param is not None:
            param['code'] = code
            param['method'] = method

            for key in self.tickIntList:
                if key in param: param[key] = int(param[key])

            #print(param)
            try:
                self.Tick.col.insert_one(param)
            except Exception as e:
                logger.error((traceback.format_exc()))

    def procTemp(self, param):
        for key in ['atr', 'powm']:
            if key in param:
                self.procMap.__setattr__(key, param[key])

    # 买入后的最高/最低价
    def getMax(self, df0, s, e, mode):
        s = str(s)[:10]
        if mode > 0:
            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] < e)].ix[:, 'close'].max()
        else:
            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] < e)].ix[:, 'close'].min()

    def order(self, cur, mode, param, isstop=0):
        # 当前tick对
        n0 = cur[self.mCodes[0]]

        # future_baseInfo 参数值
        b0 = self.baseInfo.doc(self.procMap.codes[0])
        times0 = b0["contract_multiplier"]

        preNode = self.procMap.preNode
        # 每次交易量
        v0 = (round(self.iniAmount / n0["last"] / times0, 0) *
              times0) if not preNode else preNode[0]["hands"] * times0
        # 开仓 1/ 平仓 -1
        isOpen = 0 if mode == 0 else 1

        # 买 / 卖 ,  若mode=0. 则按持仓方向平仓操作
        isBuy = -preNode[0]["mode"] if (mode == 0
                                        and preNode is not None) else mode
        # 费率
        fee0 = (v0 / times0 * b0["ratio"]) if b0["ratio"] > 0.5 else (
            b0["ratio"] * v0 *
            (n0["asks"][0] if isBuy == 1 else n0["bids"][0]))

        now = public.getDatetime()
        # 使用uuid作为批次号
        if mode != 0:
            self.procMap.batchid = uuid.uuid1()

        price = n0["asks"][0] if isBuy == 1 else n0["bids"][0]
        if price == 0:
            price = n0['close']

        doc = {
            "createdate": now,
            "code": n0["code"],
            "symbol": self.baseInfo.ctpCode(n0["code"]),
            "price": price,
            "vol": v0,
            "hands": v0 / times0,
            "ini_hands": v0 / times0,  # 提交单数
            "ini_price":
            n0["asks"][0] if isBuy == 1 else n0["bids"][0],  # 提交价格
            "mode": isBuy,
            "isopen": isOpen,
            "isstop": isstop,
            "fee": fee0,
            "income": 0,
            "rel_price": param["p_l"] if isBuy == 1 else param["p_h"],
            "rel_std": param["std"],
            "batchid": self.procMap.batchid,
            "delta": param["pow"] if 'pow' in param else 0,
            "bullwidth": param["width"],
            "widthdelta": param["wd1"],
            # "macd": param["macd"],
            "status": 0,  # 定单P执行CT返回状态
            "pstatus": int(self.procMap.status),  # 策略状态:0-bull 1,-1: trend状态
            "method": self.methodName,
            "uid": self.uid
        }

        # 下单并记录
        return self.record([doc], mode)

    def setIncome(self, orders, mode):
        doc = orders[0]
        preNode = self.procMap.preNode
        if mode == 0 and preNode is not None:
            p0 = preNode[0]
            sign = np.sign(p0["mode"])
            doc["income"] = round(
                sign * (doc["price"] - p0["price"]) * p0["vol"] - doc["fee"],
                2)
            #doc["interval"] = int(self.Rice.timeDiff(p0['createdate']))  # 间隔时间
        else:
            doc["income"] = -doc["fee"]
        return orders

    # 设置过程状态
    def setPStatus(self, status):
        """
            更改进程状态,并写入数据库,供重新启动程序时调用
        """
        self.procMap.status = status
        method = self.topTableName
        self.PStatus.setStatus('_'.join(self.procMap.codes), method, status)
        logger.info(("setPStatus", self.procMap.codes, method, status))

    def record(self, orders, mode):
        state = 0
        isOpen = 0 if mode == 0 else 1
        # 发送订单并记录到数据库
        if self.isCTPUse and self.CTP is not None and orders[0]['vol'] > 0:
            # 检查订单条件
            state = self.CTP.checkPosition(orders, isOpen)
            if state == 0:
                # 发送订单
                try:
                    self.CTP.sendOrder(orders)
                    # 检查全部执行结果
                    state, orders = self.CTP.checkResult()
                except Exception as e:
                    print(traceback.format_exc())
                    state = 2

        # 检查结果写入数据库
        if state == 0:
            # 重新计算实际收入
            self.setIncome(orders, mode)
            logger.info(
                [" purchase record: ", state, self.uid, mode, orders[0]])

            # 保存/清空 前一次操作文件 到进程变量
            self.procMap.preNode = orders if (mode != 0) else None
            self.procMap.isOpen = mode
            # 交易成功
            self.Record.insertAll(orders)
            return True

        else:
            if state < 0:
                logger.info(('----账户持仓检查不符合 ----:', state, self.uid, mode))

            elif state == 4:
                # 等待状态
                logger.info(('----检查通过,交易提交中 挂起 ----:', state, self.uid, mode))
                self.banCodeList.append(self.procMap.codes[0])
            else:
                logger.info(('----检查通过,交易不成功 ----:', state, self.uid, mode))
                self.banCodeList.append(self.procMap.codes[0])
            time.sleep(3)
            return False
예제 #4
0
class model_future_fellow5_v1(model_future_ctp):
    def __init__(self):
        # 统一参数
        super().__init__()

        self.iniAmount = 500000  # 单边50万

        self.isAutoAlterPosition = True
        self.isTest = False
        self.isTickSave = False

        self.indexCodeList = [('IH', '000016.XSHG'), ('IF', '399300.XSHE'),
                              ('IC', '399905.XSHE')]

        self.banCodeList = []  # 暂时无权限操作的code
        self.isCTPUse = False  # 是否启用CTP接口(并区分
        self.tickIntList = ['powm', 'kdjm', 'mode', 'isopen', 'isstop']

        self.cvsCodes = ['SC', 'IH']
        self.tickInterval = 1
        self.klinePeriod = 14
        self.atrLine = 2
        self.bullLine = 3.5

        self.uidStyle = '%s_14_2.0_%s_3.5_2_%s'
        self.future_Map = []
        self.batchNum = 1
        self.ctpuser = '******'
        self.methodName = 'fellow'

    def pool(self):
        pool = Pool(processes=6)
        pid = 0
        for codes in self.seperate():
            print('pool send:', pid, len(codes), codes)
            #if 'SC' not in codes: continue
            #self.start(codes)
            try:
                pool.apply_async(self.start, (codes, ))
                time.sleep(1)
                pid += 1
                # break
            except Exception as e:
                print(e)
                continue

        pool.close()
        pool.join()

    # 按结束时间分割为不同进程
    def seperate(self):
        Base = future_baseInfo()
        codes = Base.getUsedMap(hasIndex=True, isquick=True)
        dd = str(public.getTime(style='%H:%M:%S'))
        maps = {}
        # 按结束时间分组分进程
        for doc in Base.getInfo(codes):
            if doc['code'] in self.banCodeList: continue

            uid = self.uidStyle % (doc['code'], doc['quickkline'][:-1],
                                   self.methodName)
            self.future_Map.append(uid.split("_"))
            key = doc['nightEnd']
            if '03:00:00' < key < dd: continue

            if key not in maps.keys():
                maps[key] = []

            maps[key].append(doc['code'])

        for key in maps.keys():
            if len(maps[key]) < 10:
                yield maps[key]
            else:
                l, t = len(maps[key]), len(maps[key]) // 10
                for i in range(t):
                    s, e = i * 10, l if (i + 1) * 10 > l else (i + 1) * 10
                    yield maps[key][s:e]

    def start(self, full_codes):
        # print(full_codes)
        self.Record = future_orderForm()
        if not self.isCTPUse:
            self.Record.tablename = 'future_orderForm_1'

        self.time0 = time.time()

        if self.isTickSave:
            self.Tick = mon_tick()

        self.Rice = interface_Rice()
        # 基础配置信息类
        self.baseInfo = BaseInfo(full_codes, self.Rice)

        # ctp 接口类
        # self.CTP =  interface_pyctp(use=self.isCTPUse, baseInfo=self.baseInfo, userkey=self.ctpuser)

        # 进程控制类
        self.procMap = ProcessMap()

        # 设置交易对的收盘时间
        self.Rice.setTimeArea(self.baseInfo.nightEnd)

        self.indexList = []
        if len(self.indexCodeList) > 0:
            self.Rice.setIndexList(self.indexCodeList)
            self.indexList = [c[0] for c in self.indexCodeList]

        # 按k线类型分拆组,进行K线数据调用
        self.groupByKline(full_codes)
        # 初始化节点
        self.iniNode(full_codes)
        # return
        # 子进程启动
        full_mCodes = self.baseInfo.mainCodes  # 主力合约
        logger.info(
            ("%s start: %s" % (self.__class__.__name__, ",".join(full_mCodes)),
             self.Rice.TimeArea))

        self.Rice.startTick(full_mCodes,
                            kmap=self.kTypeMap,
                            source='combin',
                            callback=self.onTick)

    # 按K线类型分组
    def groupByKline(self, full_codes):
        self.used_future_Map, self.kTypeMap = [], {}
        for map in self.future_Map:
            code = map[0]
            if map[0] not in full_codes: continue
            self.used_future_Map.append(map)

            # 按k线时间框类型初始化 kTypeMap dict,
            ktype = int(map[3])
            # 字典
            self.kTypeMap[code] = ktype
            # 分组
            if ktype not in self.kTypeMap.keys():
                self.kTypeMap[ktype] = []

            mCode = self.baseInfo.mCode(code)
            if mCode not in self.kTypeMap[ktype]:
                self.kTypeMap[ktype].append(mCode)

    # 初始化节点
    def iniNode(self, full_codes):
        openMap = self.Record.getOpenMap(self.methodName,
                                         codes=full_codes,
                                         batchNum=1)

        # 非CTP方式
        for map in self.used_future_Map:
            key, uid = map[0], "_".join(map)
            self.procMap.new(uid)  # 初始化进程参数类

            # 初始化品种状态
            if key in openMap:
                self.procMap.setIni(uid, openMap[key])
                logger.info(
                    (uid, key, self.procMap.isOpen, self.procMap.status))

    # Tick 响应
    def onTick(self, tick):
        # 计算参数
        # 当前时间
        tt = str(public.getTime(style='%H:%M:%S'))
        for map in self.used_future_Map:
            if map[0] in self.banCodeList: continue

            # 股指期货时间过滤
            if map[0] in self.indexList and '08:59:00' < tt < '09:30:00':
                continue
            if map[0] not in self.indexList and '13:00:00' < tt < '13:30:00':
                continue

            self.uid = self.procMap.setUid(map, num=self.batchNum)  # uid
            self.mCodes = [self.baseInfo.mCode(c)
                           for c in self.procMap.codes]  # 当前主力合约代码
            kline = self.procMap.kline

            # 按时长读取k线数据
            dfs = self.Rice.getKline(self.kTypeMap[kline],
                                     ktype=kline,
                                     key=str(kline) + 'm',
                                     num=1)

            # 检查间隔时间
            try:
                # 计算指标
                param = self.paramCalc(dfs, tick)
                #if map[0] =='SC' and self.itemCount % 20 ==0:
                #    print(tick[self.mCodes[0]])

                if param is not None and not np.isnan(param["ma"]):
                    # mongodb Record
                    self.debugT('', param=param)

                    # 执行策略,并下单
                    self.orderCheck(tick, param)

            except Exception as e:
                print(traceback.format_exc())

    def apart(self, PS, ktype):
        apart = math.pow(
            (int(time.time()) % (60 * ktype)) * 1.0 / (60 * ktype), 0.5)
        return PS * apart + PS.shift(1) * (1 - apart)

    # 买入后的最高/最低价
    def getMax(self, df0, s, e, mode):
        if mode > 0:
            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] < e)].ix[:-1, 'close'].max()
        else:
            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] < e)].ix[:-1, 'close'].min()

    def setLastClose(self, close):
        tt = int(time.time()) // 5
        rec = self.procMap.get('Min5')
        if tt != rec:
            self.procMap.set('Min5', tt)
            ss = self.procMap.get('Min5Record')
            if ss is None:
                ss = []
                ss.append(close)
            else:
                ss.append(close)
                if len(ss) > 3: ss.pop(0)
            self.procMap.set('Min5Record', ss)

    def getLastClose(self):
        ss = self.procMap.get('Min5Record')
        if ss is None: return 0, 0
        if len(ss) < 3: return ss[-1], 0
        if len(ss) == 3: return ss[-1], ss[0]

    pointColumns = ['powm', 'diss', 'fall']

    def point(self, row, row_1, tsize):
        ma, close, open, high, low, std, stdc, atr, atrc, dd = \
            (row[key] for key in
             "ma,close,open,high,low,std,stdc,atr,atrc,datetime".split(","))

        open = row_1['close']
        tt = str(public.getTime(style='%H:%M:%S'))
        kline = self.procMap.kline

        BL = 4.0 - float(kline) / 10

        #
        apart = (60 * kline) - (int(time.time()) % (60 * kline))
        if '09:00:00' <= tt < '09:15:00' or '21:00:00' <= tt < '21:10:00' or '14:45:00' <= tt < '15:00:01':
            BL += 5.0

        if apart > 10:
            BL += 0.5

        sign = 1 if high > (ma + 2 * std) else -1 if low < (ma -
                                                            2 * std) else 0

        # 计算长度、回撤率
        max = high if sign > 0 else low if sign < 0 else close
        diss = 0 if std == 0 else abs(max - ma) / std
        fall = abs(max - close) / abs(max - open) if max != open else 0

        # 条件
        opt0 = (diss > BL) and atrc > self.atrLine
        opt1 = (diss > (BL - 0.25)) and (atrc > (self.atrLine + 1.5))

        # 超长
        opt2 = diss > (BL + 1)

        # 超回收
        opt3 = diss > (BL - 0.35) and (fall > 0.5)

        opt8 = (abs(max - close) > 3 * tsize)
        opt9 = (atr / ma) * 10000 > 8 and std > 3 * tsize

        opt10 = stdc > 1.25
        powm = 0
        if opt8 and opt9:
            if opt10:
                powm = sign if opt0 else sign * 2 if opt1 else sign * 4 if opt3 else 0

            elif opt2:
                powm = sign * 3

        # 设置整点数据
        if int(time.time()) % 5 == 0:
            self.setLastClose(close)

        return powm, diss, fall

    # 计算布林参数
    klinecolumns = ['high', 'open', 'volume', 'close', 'low']

    def paramCalc(self, dfs, cur):
        if len(dfs) == 0: return None
        period = self.klinePeriod
        c0 = cur[self.mCodes[0]]
        c0['close'] = c0['last']

        # 去掉当前的即时k线
        df0 = copy.deepcopy(dfs[self.mCodes[0]].iloc[-35:])
        # print(len(df0))
        # 计算相关参数
        columns = self.klinecolumns

        #if self.procMap.codes[0]=='SC':
        #    print(df0)

        # 添加即时K线
        df0.loc[public.getDatetime()] = pd.Series([c0[key] for key in columns],
                                                  index=columns)
        close = df0["close"]
        df0["datetime"] = df0.index

        df0["ma"] = ma = ta.MA(close, timeperiod=period)
        df0["std"] = std = ta.STDDEV(close, timeperiod=period, nbdev=1)

        df0["stdc"] = std / ta.MA(std, timeperiod=period)

        df0['atr'] = ta.ATR(df0['high'], df0['low'], close, timeperiod=period)
        df0['atrc'] = ta.ATR(df0['high'], df0['low'], close,
                             timeperiod=1) / df0['atr']
        df0["slope"] = ta.LINEARREG_SLOPE(ma, timeperiod=5)

        # kdj顶点
        kdjK, kdjD = ta.STOCH(df0["high"],
                              df0["low"],
                              close,
                              fastk_period=9,
                              slowk_period=3,
                              slowk_matype=1,
                              slowd_period=3,
                              slowd_matype=1)

        df0["kdj_d2"] = kdj_d2 = kdjK - kdjD
        df0["kdjm"] = kdj_d2 * kdj_d2.shift(1)
        df0["kdjm"] = df0.apply(
            lambda row: self.turn(row['kdjm'], row['kdj_d2'], 1), axis=1)

        b0 = self.baseInfo.doc(self.procMap.codes[0])

        self.df0 = df0
        param_1 = copy.deepcopy(df0.iloc[-2]).to_dict()
        param = copy.deepcopy(df0.iloc[-1]).to_dict()

        powm, diss, fall = self.point(param, param_1, b0['tick_size'])

        # 记录最近5/15秒点的数据
        param.update(c0)
        param.update({
            "powm": powm,
            "diss": diss,
            "fall": fall,
            #"last5":last5,
            #"last15": last15,
            "now": c0['now'],
            "p_l": c0["asks"][0],
            "p_h": c0["bids"][0],
        })
        return param

    pub = 0
    itemCount = 0

    def orderCheck(self, cur, param):
        isOpen, isRun, isstop = self.procMap.isOpen, False, 0

        powm, atr, date, kdjm, close = (
            param[key] for key in "powm,atr,datetime,kdjm,close".split(","))

        self.preNode = self.procMap.preNode

        if isOpen == 0:
            if powm != 0:
                isRun, isOpen = True, int(-powm)

        elif isOpen != 0 and self.preNode is not None:
            # 止盈止损
            kline = self.procMap.kline
            preP, s = self.preNode[0]['price'], self.preNode[0]['createdate']
            #
            apart = (60 * kline) - (int(time.time()) % (60 * kline))
            # 保持时间
            keeps = len(self.df0[self.df0['datetime'] > str(s)])

            if isOpen * kdjm < 0 and apart < 10 and keeps > 3:
                isRun, isOpen, isstop = True, 0, 1

            # 反转
            elif isOpen * powm > 0:
                if self.order(cur, 0, param, isstop=3):
                    isRun, isOpen = True, int(-powm)

            else:
                # 止损
                mp = self.getMax(self.df0, s, date, isOpen)
                sign = np.sign(isOpen)
                mp = close if np.isnan(mp) else mp

                if sign * (preP - close) > 1.5 * atr:
                    isRun, isOpen, isstop = True, 0, 4

                elif not np.isnan(mp) and (sign * (mp - close) > 3 * atr):
                    isOpen, isRun, isstop = 0, True, 5

        if isRun:
            # logger.info((self.procMap.codes[0], param))
            self.order(cur, isOpen, param, isstop=isstop)

    def order(self, cur, mode, param, isstop=0):
        # 当前tick对
        n0 = cur[self.mCodes[0]]

        # future_baseInfo 参数值
        b0 = self.baseInfo.doc(self.procMap.codes[0])
        times0 = b0["contract_multiplier"]

        preNode = self.procMap.preNode

        # 每次交易量
        code = self.procMap.codes[0]
        if preNode is not None:
            v0 = preNode[0]["hands"]
        else:
            v0 = self.iniAmount / times0 / n0['close']
            v0 = int(v0 + 0.2) if v0 > 0.8 else 1
            if v0 == 0: v0 = 1

        # 开仓 1/ 平仓 -
        isOpen = 0 if mode == 0 else 1

        # 买 / 卖 ,  若mode=0. 则按持仓方向平仓操作
        isBuy = -preNode[0]["mode"] if (mode == 0
                                        and preNode is not None) else mode

        # 费率
        fee0 = (v0 * b0["ratio"]) if b0["ratio"] > 0.5 else (
            b0["ratio"] * v0 *
            (n0["asks"][0] if isBuy == 1 else n0["bids"][0]))

        now = public.getDatetime()
        # 使用uuid作为批次号
        if mode != 0:
            self.procMap.batchid = uuid.uuid1()

        price = n0["asks"][0] if isBuy == 1 else n0["bids"][0]
        if price == 0:
            price = n0['close']

        doc = {
            "createdate": now,
            "code": n0["code"],
            "name": code,
            "symbol": self.baseInfo.ctpCode(n0["code"]),
            "price": price,
            "vol": v0 * times0,
            "hands": v0,
            "ini_hands": v0,  # 提交单数
            "ini_price": price,  # 提交价格
            "mode": int(isBuy),
            "isopen": isOpen,
            "isstop": isstop,
            "fee": fee0,
            "income": 0.0,
            "rel_price": price,
            "delta": param['diss'],
            "rel_std": param['std'],
            "widthDelta": param['atr'],
            # 'stop_price': 0 if mode == 0 else dp,
            "batchid": self.procMap.batchid,
            "status": 0,  # 定单P执行CT返回状态
            "method": self.methodName,
            "uid": self.uid
        }

        if self.isTickSave:
            monR = copy.deepcopy(param)
            monR.update(doc)
            monR.update({"type": "record"})
            self.debugR(monR)

        # 下单并记录
        if not self.isTest:
            return self.record([doc], mode)
예제 #5
0
class model_future_detect_single(model_future_ctp):
    def __init__(self):
        # 统一参数
        self.iniAmount = 500000  # 单边50万

        self.isAutoAlterPosition = True
        self.isTest = False
        self.isTickSave = False

        self.indexCodeList = [('IH', '000016.XSHG'), ('IF', '399300.XSHE'),
                              ('IC', '399905.XSHE')]
        self.banCodeList = []  # 暂时无权限操作的code
        self.isCTPUse = False  # 是否启用CTP接口(并区分

        self.klinePeriod = 14
        self.atrLine = 2
        self.bullLine = 3.5

        self.uidStyle = '%s_14_2.0_%s_3.5_2_%s'
        self.future_Map = []
        self.batchNum = 1
        self.ctpuser = '******'
        self.methodName = 'fellow'

    def pool(self):
        pool = Pool(processes=6)
        pid = 0
        for codes in self.seperate():
            print('pool send:', pid, len(codes), codes)
            #if 'ZC' not in codes: continue
            #self.start(codes)
            try:
                pool.apply_async(self.start, (codes, ))
                time.sleep(1)
                pid += 1
                #break
            except Exception as e:
                print(e)
                continue

        pool.close()
        pool.join()

    # 按结束时间分割为不同进程
    def seperate(self):
        Base = future_baseInfo()
        codes = Base.getUsedMap(hasIndex=True, isquick=True)

        maps = {}
        # 按结束时间分组分进程
        for doc in Base.getInfo(codes):
            if doc['code'] in self.banCodeList: continue

            uid = self.uidStyle % (doc['code'], doc['quickkline'][:-1],
                                   self.methodName)
            self.future_Map.append(uid.split("_"))

            key = doc['nightEnd']
            if key not in maps.keys():
                maps[key] = []

            maps[key].append(doc['code'])

        for key in maps.keys():
            if len(maps[key]) < 10:
                yield maps[key]
            else:
                l, t = len(maps[key]), len(maps[key]) // 10
                for i in range(t):
                    s, e = i * 10, l if (i + 1) * 10 > l else (i + 1) * 10
                    yield maps[key][s:e]

    def start(self, full_codes):
        # print(full_codes)
        self.Record = future_orderForm()
        if not self.isCTPUse:
            self.Record.tablename = 'future_orderForm_1'

        self.time0 = time.time()

        if self.isTickSave:
            self.Tick = mon_tick()

        self.Rice = interface_Rice()
        # 基础配置信息类
        self.baseInfo = BaseInfo(full_codes, self.Rice)

        # ctp 接口类
        #self.CTP =  interface_pyctp(use=self.isCTPUse, baseInfo=self.baseInfo, userkey=self.ctpuser)

        # 进程控制类
        self.procMap = ProcessMap()

        # 设置交易对的收盘时间
        self.Rice.setTimeArea(self.baseInfo.nightEnd)

        # 设置股指期货
        if len(self.indexCodeList) > 0:
            self.Rice.setIndexList(self.indexCodeList)

        # 按k线类型分拆组,进行K线数据调用
        self.groupByKline(full_codes)
        # 初始化节点
        self.iniNode(full_codes)
        # return
        # 子进程启动
        full_mCodes = self.baseInfo.mainCodes  # 主力合约
        logger.info(
            ("%s start: %s" % (self.__class__.__name__, ",".join(full_mCodes)),
             self.Rice.TimeArea))

        self.Rice.startTick(full_mCodes,
                            kmap=self.kTypeMap,
                            source='combin',
                            callback=self.onTick)

    # 按K线类型分组
    def groupByKline(self, full_codes):
        self.used_future_Map, self.kTypeMap = [], {}
        for map in self.future_Map:
            code = map[0]
            if map[0] not in full_codes: continue
            self.used_future_Map.append(map)

            # 按k线时间框类型初始化 kTypeMap dict,
            ktype = int(map[3])
            # 字典
            self.kTypeMap[code] = ktype
            # 分组
            if ktype not in self.kTypeMap.keys():
                self.kTypeMap[ktype] = []

            mCode = self.baseInfo.mCode(code)
            if mCode not in self.kTypeMap[ktype]:
                self.kTypeMap[ktype].append(mCode)

    # 初始化节点
    def iniNode(self, full_codes):
        openMap = self.Record.getOpenMap(self.methodName,
                                         codes=full_codes,
                                         batchNum=1)

        # 非CTP方式
        for map in self.used_future_Map:
            key, uid = map[0], "_".join(map)
            self.procMap.new(uid)  # 初始化进程参数类

            # 初始化品种状态
            if key in openMap:
                self.procMap.setIni(uid, openMap[key])
                logger.info(
                    (uid, key, self.procMap.isOpen, self.procMap.status))

    # Tick 响应
    def onTick(self, tick):
        # 计算参数
        for map in self.used_future_Map:
            if map[0] in self.banCodeList: continue
            self.uid = self.procMap.setUid(map, num=self.batchNum)  # uid
            self.mCodes = [self.baseInfo.mCode(c)
                           for c in self.procMap.codes]  # 当前主力合约代码
            kline = self.procMap.kline

            # 按时长读取k线数据
            dfs = self.Rice.getKline(self.kTypeMap[kline],
                                     ktype=kline,
                                     key=str(kline) + 'm',
                                     num=1)

            # 检查间隔时间
            try:
                # 计算指标
                param = self.paramCalc(dfs, tick)
                if param is not None and not np.isnan(param["ma"]):
                    # 执行策略,并下单
                    self.orderCheck(tick, param)

            except Exception as e:
                print(traceback.format_exc())

    def apart(self, PS, ktype):
        apart = math.pow(
            (int(time.time()) % (60 * ktype)) * 1.0 / (60 * ktype), 0.5)
        return PS * apart + PS.shift(1) * (1 - apart)

    # 买入后的最高/最低价
    def getMax(self, df0, s, e, mode):
        if mode > 0:
            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] < e)].ix[:-1, 'close'].max()
        else:
            return df0[(df0['datetime'] >= s)
                       & (df0['datetime'] < e)].ix[:-1, 'close'].min()

    pointColumns = ['powm', 'diss']

    def point(self, row):
        ma, close, high, low, std, stdc, atr, atrc, dd = \
            (row[key] for key in
             "ma,close,high,low,std,stdc,atr,atrc,datetime".split(","))

        sign = 1 if high > (ma + 2 * std) else -1 if low < (ma -
                                                            2 * std) else 0

        max = high if sign > 0 else low if sign < 0 else close
        diss = 0 if std == 0 else abs(max - ma) / std

        opt0 = (diss > self.bullLine) and atrc > self.atrLine
        opt1 = (diss >
                (self.bullLine - 0.5)) and (atrc >
                                            (self.atrLine + 1) or stdc > 1.5)
        opt2 = diss > (self.bullLine + 1)

        opt3 = abs(max - close) > 0.2 * atr
        opt4 = (atr / ma) * 10000 > 7

        powm = sign if ((opt0 or opt1 or opt2) and opt3 and opt4) else 0

        columns = self.pointColumns
        return pd.Series([powm, diss], index=columns)

# 计算布林参数

    def paramCalc(self, dfs, cur):
        if len(dfs) == 0: return None
        period = self.klinePeriod
        c0 = cur[self.mCodes[0]]
        c0['close'] = c0['last']

        # 去掉当前的即时k线
        df0 = copy.deepcopy(dfs[self.mCodes[0]].iloc[-40:])
        #print(len(df0))
        # 计算相关参数
        columns = df0.columns
        # 添加即时K线
        df0.loc[public.getDatetime()] = pd.Series([c0[key] for key in columns],
                                                  index=columns)
        close = df0["close"]
        df0["datetime"] = df0.index

        df0["ma"] = ma = ta.MA(close, timeperiod=period)
        df0["std"] = std = ta.STDDEV(close, timeperiod=period, nbdev=1)

        df0["stdc"] = std / ta.MA(std, timeperiod=period)

        df0['atr'] = ta.ATR(df0['high'], df0['low'], close, timeperiod=period)
        df0['atrr'] = df0['atr'] / ma * 10000
        df0['atrc'] = ta.ATR(df0['high'], df0['low'], close,
                             timeperiod=1) / df0['atr']

        # kdj顶点
        kdjK, kdjD = ta.STOCH(df0["high"],
                              df0["low"],
                              close,
                              fastk_period=5,
                              slowk_period=3,
                              slowk_matype=1,
                              slowd_period=3,
                              slowd_matype=1)

        df0["kdj_d2"] = kdj_d2 = kdjK - kdjD
        df0["kdjm"] = kdj_d2 * kdj_d2.shift(1)
        df0["kdjm"] = df0.apply(
            lambda row: self.turn(row['kdjm'], row['kdj_d2'], 1), axis=1)

        df1 = df0.apply(lambda row: self.point(row), axis=1)
        for key in self.pointColumns:
            df0[key] = df1[key]

        param = copy.deepcopy(df0.iloc[-1]).to_dict()
        self.df0 = df0
        param.update({"p_l": c0["asks"][0], "p_h": c0["bids"][0]})
        return param

    pub = 0
    itemCount = 0

    def orderCheck(self, cur, param):
        isOpen, isRun, isstop = self.procMap.isOpen, False, 0

        powm, atr, date, kdjm, close = (
            param[key] for key in "powm,atr,datetime,kdjm,close".split(","))

        self.preNode = self.procMap.preNode

        if isOpen == 0:
            if powm != 0:
                isRun, isOpen = True, int(-powm)

        elif isOpen != 0 and self.preNode is not None:
            # 止盈止损
            kline = self.procMap.kline
            preP, s = self.preNode[0]['price'], self.preNode[0]['createdate']

            apart = (60 * kline) - (int(time.time()) % (60 * kline))
            keeps = len(self.df0[self.df0['datetime'] > str(s)])

            if isOpen * kdjm < 0 and apart < 10 and keeps > 3:
                isRun, isOpen, isstop = True, 0, 1

            else:

                mp = self.getMax(self.df0, s, date, isOpen)
                mp = close if np.isnan(mp) else mp

                if np.sign(isOpen) * (preP - close) > 1.5 * atr:
                    isRun, isOpen, isstop = True, 0, 4

                elif not np.isnan(mp) and (np.sign(isOpen) *
                                           (mp - close) > 3.0 * atr):
                    isOpen, isRun, isstop = 0, True, 5

                # 反转
                elif isOpen * powm > 0:
                    if self.order(cur, isOpen, param, isstop=3):
                        isRun, isOpen = True, int(-powm)

        if isRun:
            #logger.info((self.procMap.codes[0], param))
            self.order(cur, isOpen, param, isstop=isstop)

    def order(self, cur, mode, param, isstop=0):
        # 当前tick对
        n0 = cur[self.mCodes[0]]

        # future_baseInfo 参数值
        b0 = self.baseInfo.doc(self.procMap.codes[0])
        times0 = b0["contract_multiplier"]

        preNode = self.procMap.preNode

        # 每次交易量
        code = self.procMap.codes[0]
        if preNode is not None:
            v0 = preNode[0]["hands"]
        else:
            v0 = self.iniAmount / times0 / n0['close']
            v0 = int(v0 + 0.2) if v0 > 0.8 else 1
            if v0 == 0: v0 = 1

        # 开仓 1/ 平仓 -
        isOpen = 0 if mode == 0 else 1

        # 买 / 卖 ,  若mode=0. 则按持仓方向平仓操作
        isBuy = -preNode[0]["mode"] if (mode == 0
                                        and preNode is not None) else mode
        # 费率
        fee0 = (v0 * b0["ratio"]) if b0["ratio"] > 0.5 else (
            b0["ratio"] * v0 *
            (n0["asks"][0] if isBuy == 1 else n0["bids"][0]))

        now = public.getDatetime()
        # 使用uuid作为批次号
        if mode != 0:
            self.procMap.batchid = uuid.uuid1()

        price = n0["asks"][0] if isBuy == 1 else n0["bids"][0]
        if price == 0:
            price = n0['close']

        doc = {
            "createdate": now,
            "code": n0["code"],
            "name": code,
            "symbol": self.baseInfo.ctpCode(n0["code"]),
            "price": price,
            "vol": v0 * times0,
            "hands": v0,
            "ini_hands": v0,  # 提交单数
            "ini_price":
            n0["asks"][0] if isBuy == 1 else n0["bids"][0],  # 提交价格
            "mode": int(isBuy),
            "isopen": isOpen,
            "isstop": isstop,
            "fee": fee0,
            "income": 0,
            "rel_price": param["p_l"] if isBuy == 1 else param["p_h"],
            #'stop_price': 0 if mode == 0 else dp,
            "batchid": self.procMap.batchid,
            "status": 0,  # 定单P执行CT返回状态
            "method": self.methodName,
            "uid": self.uid
        }

        # 下单并记录
        if not self.isTest:
            return self.record([doc], mode)