class QAStrategyStockBase(QAStrategyCTABase): def __init__(self, code=['000001'], frequence='1min', strategy_id='QA_STRATEGY', risk_check_gap=1, portfolio='default', start='2019-01-01', end='2019-10-21', send_wx=False, market_type='stock_cn', data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=None, mongo_ip=mongo_ip): super().__init__(code=code, frequence=frequence, strategy_id=strategy_id, risk_check_gap=risk_check_gap, portfolio=portfolio, start=start, end=end, send_wx=send_wx, data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=taskid, mongo_ip=mongo_ip) self.code = code self.send_wx = send_wx def subscribe_data(self, code, frequence, data_host, data_port, data_user, data_password): """[summary] Arguments: code {[type]} -- [description] frequence {[type]} -- [description] """ self.sub = subscriber_topic( exchange='realtime_stock_{}'.format(frequence), host=data_host, port=data_port, user=data_user, password=data_password, routing_key='') for item in code: self.sub.add_sub(exchange='realtime_stock_{}'.format(frequence), routing_key=item) self.sub.callback = self.callback def upcoming_data(self, new_bar): """upcoming_bar : Arguments: new_bar {json} -- [description] """ self._market_data = pd.concat([self._old_data, new_bar]) # QA.QA_util_log_info(self._market_data) if self.isupdate: self.update() self.isupdate = False self.update_account() # self.positions.on_price_change(float(new_bar['close'])) self.on_bar(new_bar) def ind2str(self, ind, ind_type): z = ind.tail(1).reset_index().to_dict(orient='records')[0] return json.dumps({ 'topic': ind_type, 'code': self.code, 'type': self.frequence, 'data': z }) def callback(self, a, b, c, body): """在strategy的callback中,我们需要的是 1. 更新数据 2. 更新bar 3. 更新策略状态 4. 推送事件 Arguments: a {[type]} -- [description] b {[type]} -- [description] c {[type]} -- [description] body {[type]} -- [description] """ self.new_data = json.loads(str(body, encoding='utf-8')) self.latest_price[self.new_data['code']] = self.new_data['close'] self.running_time = self.new_data['datetime'] if self.dt != str(self.new_data['datetime'])[0:16]: # [0:16]是分钟线位数 print('update!!!!!!!!!!!!') self.dt = str(self.new_data['datetime'])[0:16] self.isupdate = True self.acc.on_price_change(self.new_data['code'], self.new_data['close']) bar = pd.DataFrame([self.new_data]).set_index( ['datetime', 'code']).loc[:, ['open', 'high', 'low', 'close', 'volume']] self.upcoming_data(bar) def _debug_sim(self): self.running_mode = 'sim' self._old_data = QA.QA_fetch_stock_min( self.code, QA.QA_util_get_last_day( QA.QA_util_get_real_date(str(datetime.date.today()))), str(datetime.datetime.now()), format='pd', frequence=self.frequence).set_index(['datetime', 'code']) self._old_data = self._old_data.loc[:, [ 'open', 'high', 'low', 'close', 'volume' ]] self.database = pymongo.MongoClient(mongo_ip).QAREALTIME self.client = self.database.account self.subscriber_client = self.database.subscribe self.acc = QIFI_Account(username=self.strategy_id, password=self.strategy_id, trade_host=mongo_ip) self.acc.initial() self.pub = publisher_routing(exchange='QAORDER_ROUTER', host=self.trade_host, port=self.trade_port, user=self.trade_user, password=self.trade_password) self.subscribe_data(self.code, self.frequence, self.data_host, self.data_port, self.data_user, self.data_password) self.database.strategy_schedule.job_control.update( {'strategy_id': self.strategy_id}, { 'strategy_id': self.strategy_id, 'taskid': self.taskid, 'filepath': os.path.abspath(__file__), 'status': 200 }, upsert=True) # threading.Thread(target=, daemon=True).start() self.sub.start() def run(self): while True: pass def debug(self): self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.acc = port.new_accountpro(account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type, frequence=self.frequence) #self.positions = self.acc.get_position(self.code) print(self.acc) print(self.acc.market_type) data = QA.QA_quotation(self.code, self.start, self.end, source=QA.DATASOURCE.MONGO, frequence=self.frequence, market=self.market_type, output=QA.OUTPUT_FORMAT.DATASTRUCT) data.data.apply(self.x1, axis=1) def update_account(self): if self.running_mode == 'sim': QA.QA_util_log_info('{} UPDATE ACCOUNT'.format( str(datetime.datetime.now()))) self.accounts = self.acc.account_msg self.orders = self.acc.orders self.positions = self.acc.positions self.trades = self.acc.trades self.updatetime = self.acc.dtstr elif self.running_mode == 'backtest': #self.positions = self.acc.get_position(self.code) self.positions = self.acc.positions def send_order( self, direction='BUY', offset='OPEN', code=None, price=3925, volume=10, order_id='', ): towards = eval('ORDER_DIRECTION.{}_{}'.format(direction, offset)) order_id = str(uuid.uuid4()) if order_id == '' else order_id if self.market_type == QA.MARKET_TYPE.STOCK_CN: """ 在此对于股票的部分做一些转换 """ if towards == ORDER_DIRECTION.SELL_CLOSE: towards = ORDER_DIRECTION.SELL elif towards == ORDER_DIRECTION.BUY_OPEN: towards = ORDER_DIRECTION.BUY if isinstance(price, float): pass elif isinstance(price, pd.Series): price = price.values[0] if self.running_mode == 'sim': QA.QA_util_log_info( '============ {} SEND ORDER =================='.format( order_id)) QA.QA_util_log_info( 'direction{} offset {} price{} volume{}'.format( direction, offset, price, volume)) if self.check_order(direction, offset): self.last_order_towards = {'BUY': '', 'SELL': ''} self.last_order_towards[direction] = offset now = str(datetime.datetime.now()) order = self.acc.send_order(code=code, towards=towards, price=price, amount=volume, order_id=order_id) order['topic'] = 'send_order' self.pub.pub(json.dumps(order), routing_key=self.strategy_id) self.acc.make_deal(order) self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id if self.send_wx: for user in self.subscriber_list: QA.QA_util_log_info(self.subscriber_list) try: "oL-C4w2WlfyZ1vHSAHLXb2gvqiMI" """http://www.yutiansut.com/signal?user_id=oL-C4w1HjuPRqTIRcZUyYR0QcLzo&template=xiadan_report&\ strategy_id=test1&realaccount=133496&code=rb1910&order_direction=BUY&\ order_offset=OPEN&price=3600&volume=1&order_time=20190909 """ requests.post( 'http://www.yutiansut.com/signal?user_id={}&template={}&strategy_id={}&realaccount={}&code={}&order_direction={}&order_offset={}&price={}&volume={}&order_time={}' .format(user, "xiadan_report", self.strategy_id, self.acc.user_id, code, direction, offset, price, volume, now)) except Exception as e: QA.QA_util_log_info(e) else: QA.QA_util_log_info('failed in ORDER_CHECK') elif self.running_mode == 'backtest': self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id self.acc.receive_simpledeal(code=code, trade_time=self.running_time, trade_towards=towards, trade_amount=volume, trade_price=price, order_id=order_id)
class QAStrategyCTABase(): def __init__(self, code='rb1905', frequence='1min', strategy_id='QA_STRATEGY', risk_check_gap=1, portfolio='default', start='2019-01-01', end='2019-10-21', init_cash=1000000, send_wx=False, data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=None, mongo_ip=mongo_ip, model= 'py'): """ code 可以传入单个标的 也可以传入一组标的(list) 会自动基于code来判断是什么市场 TODO: 支持多个市场同时存在 """ self.trade_host = trade_host self.code = code self.frequence = frequence self.strategy_id = strategy_id self.portfolio = portfolio self.data_host = data_host self.data_port = data_port self.data_user = data_user self.data_password = data_password self.trade_host = trade_host self.trade_port = trade_port self.trade_user = trade_user self.trade_password = trade_password self.start = start self.end = end self.init_cash = init_cash self.taskid = taskid self.running_time = '' self.market_preset = QA.QAARP.MARKET_PRESET() self._market_data = [] self.risk_check_gap = risk_check_gap self.latest_price = {} self.isupdate = False self.model = model self.new_data = {} self._systemvar = {} self._signal = [] self.send_wx = send_wx if isinstance(self.code, str): self.last_order_towards = {self.code: {'BUY': '', 'SELL': ''}} else: self.last_order_towards = dict(zip(self.code, [{'BUY': '', 'SELL': ''} for i in range(len(self.code))])) self.dt = '' if isinstance(self.code, str): self.market_type = MARKET_TYPE.FUTURE_CN if re.search( r'[a-zA-z]+', self.code) else MARKET_TYPE.STOCK_CN else: self.market_type = MARKET_TYPE.FUTURE_CN if re.search( r'[a-zA-z]+', self.code[0]) else MARKET_TYPE.STOCK_CN self.bar_order = {'BUY_OPEN': 0, 'SELL_OPEN': 0, 'BUY_CLOSE': 0, 'SELL_CLOSE': 0} self._num_cached = 120 self._cached_data = [] self.user_init() @property def bar_id(self): return len(self._market_data) def _debug_sim(self): self.running_mode = 'sim' if self.frequence.endswith('min'): if isinstance(self.code, str): self._old_data = QA.QA_fetch_get_future_min('tdx', self.code.upper(), QA.QA_util_get_last_day( QA.QA_util_get_real_date(str(datetime.date.today()))), str(datetime.datetime.now()), self.frequence)[:-1].set_index(['datetime', 'code']) self._old_data = self._old_data.assign(volume=self._old_data.trade).loc[:, [ 'open', 'high', 'low', 'close', 'volume']] else: self._old_data = pd.concat([QA.QA_fetch_get_future_min('tdx', item.upper(), QA.QA_util_get_last_day( QA.QA_util_get_real_date(str(datetime.date.today()))), str(datetime.datetime.now()), self.frequence)[:-1].set_index(['datetime', 'code']) for item in self.code], sort=False) self._old_data = self._old_data.assign(volume=self._old_data.trade).loc[:, [ 'open', 'high', 'low', 'close', 'volume']] else: self._old_data = pd.DataFrame() self.database = pymongo.MongoClient(mongo_ip).QAREALTIME self.client = self.database.account self.subscriber_client = self.database.subscribe self.acc = QIFI_Account( username=self.strategy_id, password=self.strategy_id, trade_host=mongo_ip, init_cash=self.init_cash) self.acc.initial() self.pub = publisher_routing(exchange='QAORDER_ROUTER', host=self.trade_host, port=self.trade_port, user=self.trade_user, password=self.trade_password) if isinstance(self.code, str): self.subscribe_data(self.code.lower(), self.frequence, self.data_host, self.data_port, self.data_user, self.data_password, self.model) else: self.subscribe_multi(self.code, self.frequence, self.data_host, self.data_port, self.data_user, self.data_password, self.model) print('start sim') self.database.strategy_schedule.job_control.update( {'strategy_id': self.strategy_id}, {'strategy_id': self.strategy_id, 'taskid': self.taskid, 'filepath': os.path.abspath(__file__), 'status': 200}, upsert=True) def debug_sim(self): self._debug_sim() threading.Thread(target=self.sub.start, daemon=True).start() def run_sim(self): self._debug_sim() self.sub.start() def run_backtest(self): self.debug() self.acc.save() risk = QA_Risk(self.acc) risk.save() try: """add rank flow if exist QARank是我们内部用于评价策略ELO的库 此处并不影响正常使用 """ from QARank import QA_Rank QA_Rank(self.acc).send() except: pass def user_init(self): """ 用户自定义的init过程 """ pass def debug(self): self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.acc = port.new_accountpro( account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type) self.positions = self.acc.get_position(self.code) print(self.acc) print(self.acc.market_type) data = QA.QA_quotation(self.code.upper(), self.start, self.end, source=QA.DATASOURCE.MONGO, frequence=self.frequence, market=self.market_type, output=QA.OUTPUT_FORMAT.DATASTRUCT) data.data.apply(self.x1, axis=1) def x1(self,item): # print(data) self.latest_price[item.name[1]] = item['close'] if str(item.name[0])[0:10] != str(self.running_time)[0:10]: self.on_dailyclose() self.on_dailyopen() if self.market_type == QA.MARKET_TYPE.STOCK_CN: print('backtest: Settle!') self.acc.settle() self._on_1min_bar() self._market_data.append(item) self.running_time = str(item.name[0]) self.on_bar(item) def debug_t0(self): self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.acc = port.new_accountpro( account_cookie=self.strategy_id, init_cash=self.init_cash, init_hold={ self.code: 100000}, market_type=self.market_type, running_environment=RUNNING_ENVIRONMENT.TZERO) self.positions = self.acc.get_position(self.code) print(self.acc) print(self.acc.market_type) data = QA.QA_quotation(self.code.upper(), self.start, self.end, source=QA.DATASOURCE.MONGO, frequence=self.frequence, market=self.market_type, output=QA.OUTPUT_FORMAT.DATASTRUCT) def x1(item): # print(data) self.latest_price[item.name[1]] = item['close'] if str(item.name[0])[0:10] != str(self.running_time)[0:10]: self.on_dailyclose() for order in self.acc.close_positions_order: order.trade('closebySys', order.price, order.amount, order.datetime) self.on_dailyopen() if self.market_type == QA.MARKET_TYPE.STOCK_CN: print('backtest: Settle!') self.acc.settle() self._on_1min_bar() self._market_data.append(item) self.running_time = str(item.name[0]) self.on_bar(item) data.data.apply(x1, axis=1) def debug_currenttick(self, freq): data = QA.QA_fetch_get_future_transaction_realtime( 'tdx', self.code.upper()) self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.strategy_id = self.strategy_id + 'currenttick_{}_{}'.format(str(datetime.date.today()), freq) self.acc = port.new_accountpro( account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type) self.positions = self.acc.get_position(self.code) data = data.assign(price=data.price/1000).loc[:, ['code', 'price', 'volume']].resample( freq).apply({'code': 'last', 'price': 'ohlc', 'volume': 'sum'}).dropna() data.columns = data.columns.droplevel(0) data = data.reset_index().set_index(['datetime', 'code']) def x1(item): self.latest_price[item.name[1]] = item['close'] if str(item.name[0])[0:10] != str(self.running_time)[0:10]: self.on_dailyclose() self.on_dailyopen() self._on_1min_bar() self._market_data.append(item) self.running_time = str(item.name[0]) self.on_bar(item) data.apply(x1, axis=1) def debug_histick(self, freq): data = QA.QA_fetch_get_future_transaction( 'tdx', self.code.upper(), self.start, self.end) self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.strategy_id = self.strategy_id + 'histick_{}_{}_{}'.format(self.start, self.end, freq) self.acc = port.new_accountpro( account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type) self.positions = self.acc.get_position(self.code) data = data.assign(price=data.price/1000).loc[:, ['code', 'price', 'volume']].resample( freq).apply({'code': 'last', 'price': 'ohlc', 'volume': 'sum'}).dropna() data.columns = data.columns.droplevel(0) data = data.reset_index().set_index(['datetime', 'code']) def x1(item): self.latest_price[item.name[1]] = item['close'] if str(item.name[0])[0:10] != str(self.running_time)[0:10]: self.on_dailyclose() self.on_dailyopen() self._on_1min_bar() self._market_data.append(item) self.running_time = str(item.name[0]) self.on_bar(item) data.apply(x1, axis=1) def subscribe_data(self, code, frequence, data_host, data_port, data_user, data_password, model='py'): """[summary] Arguments: code {[type]} -- [description] frequence {[type]} -- [description] """ if frequence.endswith('min'): if model == 'py': self.sub = subscriber(exchange='realtime_{}_{}'.format( frequence, code), host=data_host, port=data_port, user=data_user, password=data_password) elif model == 'rust': self.sub = subscriber_routing(exchange='realtime_{}'.format( code), routing_key = frequence, host=data_host, port=data_port, user=data_user, password=data_password) self.sub.callback = self.callback elif frequence.endswith('s'): import re self._num_cached = 2*int(re.findall(r'\d+',self.frequence)[0]) self.sub = subscriber_routing(exchange='CTPX', routing_key=code, host=data_host, port=data_port, user=data_user, password=data_password) self.sub.callback = self.second_callback elif frequence.endswith('tick'): self._num_cached = 1 self.sub = subscriber_routing(exchange='CTPX', routing_key=code, host=data_host, port=data_port, user=data_user, password=data_password) self.sub.callback = self.tick_callback def subscribe_multi(self, codelist, frequence, data_host, data_port, data_user, data_password, model='py'): if frequence.endswith('min'): if model == 'rust': self.sub = subscriber_routing(exchange='realtime_{}'.format( codelist[0]), routing_key=frequence, host=data_host, port=data_port, user=data_user, password=data_password) for item in codelist[1:]: self.sub.add_sub(exchange='realtime_{}'.format( item), routing_key=frequence) elif model == 'py': self.sub = subscriber_routing(exchange='realtime_{}'.format( codelist[0].lower()), routing_key=frequence, host=data_host, port=data_port, user=data_user, password=data_password) for item in codelist[1:]: print(item) self.sub.add_sub(exchange='realtime_{}'.format( item.lower()), routing_key=frequence) self.sub.callback = self.callback elif frequence.endswith('tick'): self._num_cached = 1 self.sub = subscriber_routing(exchange='CTPX', routing_key=codelist[0].lower(), host=data_host, port=data_port, user=data_user, password=data_password) for item in codelist[1:]: print(item) self.sub.add_sub(exchange='CTPX', routing_key=item.lower()) self.sub.callback = self.tick_callback @property def old_data(self): return self._old_data def update(self): """ 此处是切换bar的时候的节点 """ self._old_data = self._market_data self._on_1min_bar() @property def market_datetime(self): return self.market_data.index.levels[0] @property def market_data(self): if self.running_mode == 'sim': return self._market_data elif self.running_mode == 'backtest': return pd.concat(self._market_data[-100:], axis=1, sort=False).T def force_close(self): # 强平 if self.positions.volume_long > 0: self.send_order('SELL', 'CLOSE', price=self.positions.last_price, volume=self.positions.volume_long) if self.positions.volume_short > 0: self.send_order('BUY', 'CLOSE', price=self.positions.last_price, volume=self.positions.volume_short) def upcoming_data(self, new_bar): """upcoming_bar : Arguments: new_bar {pd.DataFrame} -- [description] """ code = new_bar.index.levels[1][0] if len(self._old_data)> 0: self._market_data = pd.concat([self._old_data, new_bar], sort=False) else: self._market_data = new_bar #QA.QA_util_log_info(self._market_data) if self.isupdate: self.update() self.isupdate = False self.update_account() if isinstance(self.code, str): self.positions.on_price_change(float(self.latest_price[code])) else: for item in self.code: self.acc.get_position(item).on_price_change(float(self.latest_price[code])) self.on_bar(json.loads(new_bar.reset_index().to_json(orient='records'))[0]) def ind2str(self, ind, ind_type): z = ind.tail(1).reset_index().to_dict(orient='records')[0] return json.dumps({'topic': ind_type, 'code': self.code, 'type': self.frequence, 'data': z}) def second_callback(self, a, b, c, body): """在strategy的callback中,我们需要的是 1. 更新数据 2. 更新bar 3. 更新策略状态 4. 推送事件 Arguments: a {[type]} -- [description] b {[type]} -- [description] c {[type]} -- [description] body {[type]} -- [description] second ==> 2*second tick b'{"ask_price_1": 4145.0, "ask_price_2": 0, "ask_price_3": 0, "ask_price_4": 0, "ask_price_5": 0, "ask_volume_1": 69, "ask_volume_2": 0, "ask_volume_3": 0, "ask_volume_4": 0, "ask_volume_5": 0, "average_price": 61958.14258714826, "bid_price_1": 4143.0, "bid_price_2": 0, "bid_price_3": 0, "bid_price_4": 0, "bid_price_5": 0, "bid_volume_1": 30, "bid_volume_2": 0, "bid_volume_3": 0, "bid_volume_4": 0, "bid_volume_5": 0, "datetime": "2019-11-20 01:57:08", "exchange": "SHFE", "gateway_name": "ctp", "high_price": 4152.0, "last_price": 4144.0, "last_volume": 0, "limit_down": 3872.0, "limit_up": 4367.0, "local_symbol": "ag1912.SHFE", "low_price": 4105.0, "name": "", "open_interest": 277912.0, "open_price": 4140.0, "preSettlementPrice": 4120.0, "pre_close": 4155.0, "symbol": "ag1912", "volume": 114288}' tick 会基于热数据的量 self._num_cached 来判断更新/重采样 """ self.new_data = json.loads(str(body, encoding='utf-8')) self._cached_data.append(self.new_data) self.latest_price[self.code] = self.new_data['last_price'] # if len(self._cached_data) == self._num_cached: # self.isupdate = True if len(self._cached_data) > 3*self._num_cached: # 控制缓存数据量 self._cached_data = self._cached_data[self._num_cached:] data= pd.DataFrame(self._cached_data).loc[:,['datetime','last_price', 'volume']] data = data.assign(datetime= pd.to_datetime(data.datetime)).set_index('datetime').resample( self.frequence).apply({'last_price': 'ohlc', 'volume': 'last'}).dropna() data.columns = data.columns.droplevel(0) data = data.assign(volume=data.volume.diff(), code=self.code) data = data.reset_index().set_index(['datetime', 'code']) self.acc.on_price_change(self.code, self.latest_price[self.code]) # .loc[:, ['open', 'high', 'low', 'close', 'volume', 'tradetime']] now = datetime.datetime.now() if now.hour == 20 and now.minute == 59 and now.second < 10: self.daily_func() time.sleep(10) self.running_time = self.new_data['datetime'] #print(data.iloc[-1].index[0]) if self.dt != data.index[-1][0]: self.isupdate = True self.dt = data.index[-1][0] self.upcoming_data(data.tail(1)) def tick_callback(self, a, b, c, body): self.new_data = json.loads(str(body, encoding='utf-8')) self.on_tick(self.new_data) def get_code_marketdata(self, code): return self.market_data.loc[(slice(None), code), :] def get_current_marketdata(self): return self.market_data.loc[(self.running_time, slice(None)), :] def callback(self, a, b, c, body): """在strategy的callback中,我们需要的是 1. 更新数据 2. 更新bar 3. 更新策略状态 4. 推送事件 Arguments: a {[type]} -- [description] b {[type]} -- [description] c {[type]} -- [description] body {[type]} -- [description] """ self.new_data = json.loads(str(body, encoding='utf-8')) #print(self.new_data) self.latest_price[self.new_data['code']] = self.new_data['close'] if self.dt != str(self.new_data['datetime'])[0:16]: # [0:16]是分钟线位数 print('update!!!!!!!!!!!!') self.dt = str(self.new_data['datetime'])[0:16] self.isupdate = True self.acc.on_price_change(self.new_data['code'], self.new_data['close']) # .loc[:, ['open', 'high', 'low', 'close', 'volume', 'tradetime']] bar = pd.DataFrame([self.new_data]).set_index(['datetime', 'code']) now = datetime.datetime.now() if now.hour == 20 and now.minute == 59 and now.second < 10: self.daily_func() time.sleep(10) # res = self.job_control.find_one( # {'strategy_id': self.strategy_id, 'strategy_id': self.strategy_id}) # self.control_status(res) self.running_time = self.new_data['datetime'] print('send to upcoming data') self.upcoming_data(bar) def control_status(self, res): print(res) def add_subscriber(self, qaproid): """Add a subscriber 增加订阅者的QAPRO_ID """ self.subscriber_client.insert_one( {'strategy_id': self.strategy_id, 'user_id': qaproid}) @property def subscriber_list(self): """订阅者 Returns: [type] -- [description] """ return list(set([item['user_id'] for item in self.subscriber_client.find({'strategy_id': self.strategy_id})])) def load_strategy(self): raise NotImplementedError def on_dailyopen(self): pass def on_dailyclose(self): pass def on_bar(self, bar): raise NotImplementedError def on_tick(self, tick): raise NotImplementedError def _on_1min_bar(self): #raise NotImplementedError if len(self._systemvar.keys()) > 0: self._signal.append(copy.deepcopy(self._systemvar)) try: self.on_1min_bar() except: pass def on_1min_bar(self): raise NotImplementedError def on_5min_bar(self): raise NotImplementedError def on_15min_bar(self): raise NotImplementedError def on_30min_bar(self): raise NotImplementedError def order_handler(self): self._orders = {} def daily_func(self): QA.QA_util_log_info('DAILY FUNC') def risk_check(self): pass def plot(self, name, data, format): """ plot是可以存储你的临时信息的接口, 后期会接入可视化 Arguments: name {[type]} -- [description] data {[type]} -- [description] format {[type]} -- [description] """ self._systemvar[name] = {'datetime': copy.deepcopy(str( self.running_time)), 'value': data, 'format': format} def get_code(self): if isinstance(self.code, str): return self.code else: return self.code[0] def check_order(self, direction, offset, code= None): """[summary] 同方向不开仓 只对期货市场做限制 buy - open sell - close """ if code == None: code = self.get_code() if self.market_type == QA.MARKET_TYPE.FUTURE_CN: if self.last_order_towards[code][direction] == str(offset): return False else: return True else: return True def on_ordererror(self, direction, offset, price, volume): print('order Error ') def receive_simpledeal(self, code: str, trade_time, trade_amount, direction, offset, trade_price, message='sell_open'): self.send_order(direction=direction, offset=offset, volume=trade_amount, price=trade_price, order_id=QA.QA_util_random_with_topic(self.strategy_id)) def send_order(self, direction='BUY', offset='OPEN', price=3925, volume=10, order_id='', code = None): if code == None: code = self.get_code() towards = eval('ORDER_DIRECTION.{}_{}'.format(direction, offset)) order_id = str(uuid.uuid4()) if order_id == '' else order_id if isinstance(price, float): pass elif isinstance(price, pd.Series): price = price.values[0] if self.running_mode == 'sim': # 在此处拦截无法下单的订单 if (direction == 'BUY' and self.latest_price[code] <= price) or (direction == 'SELL' and self.latest_price[code] >= price): QA.QA_util_log_info( '============ {} SEND ORDER =================='.format(order_id)) QA.QA_util_log_info('direction{} offset {} price{} volume{}'.format( direction, offset, price, volume)) if self.check_order(direction, offset, code=code): #self.last_order_towards = {'BUY': '', 'SELL': ''} self.last_order_towards[code][direction] = offset now = str(datetime.datetime.now()) order = self.acc.send_order( code=code, towards=towards, price=price, amount=volume, order_id=order_id) print(order) order['topic'] = 'send_order' self.pub.pub( json.dumps(order), routing_key=self.strategy_id) self.acc.make_deal(order) self.bar_order['{}_{}'.format( direction, offset)] = self.bar_id if self.send_wx: for user in self.subscriber_list: QA.QA_util_log_info(self.subscriber_list) try: requests.post('http://www.yutiansut.com/signal?user_id={}&template={}&strategy_id={}&realaccount={}&code={}&order_direction={}&order_offset={}&price={}&volume={}&order_time={}'.format( user, "xiadan_report", self.strategy_id, self.acc.user_id, code.lower(), direction, offset, price, volume, now)) except Exception as e: QA.QA_util_log_info(e) else: QA.QA_util_log_info('failed in ORDER_CHECK') else: self.on_ordererror(direction, offset, price, volume) elif self.running_mode == 'backtest': self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id if self.market_type == 'stock_cn': order = self.acc.send_order( code=self.code, amount=volume, time=self.running_time, towards=towards, price=price) order.trade(order.order_id, order.price, order.amount, order.datetime) else: self.acc.receive_simpledeal( code=self.code, trade_time=self.running_time, trade_towards=towards, trade_amount=volume, trade_price=price, order_id=order_id, realorder_id=order_id, trade_id=order_id) self.positions = self.acc.get_position(self.code) def update_account(self): if self.running_mode == 'sim': QA.QA_util_log_info('{} UPDATE ACCOUNT'.format( str(datetime.datetime.now()))) self.accounts = self.acc.account_msg self.orders = self.acc.orders if isinstance(self.code, str): self.positions = self.acc.get_position(self.code) else: pass self.trades = self.acc.trades self.updatetime = self.acc.dtstr elif self.running_mode == 'backtest': self.positions = self.acc.get_position(self.code) def get_exchange(self, code): return self.market_preset.get_exchange(code) def get_positions(self, code): if self.running_mode == 'sim': self.update_account() return self.acc.get_position(code) elif self.running_mode == 'backtest': return self.acc.get_position(code) def get_cash(self): if self.running_mode == 'sim': self.update_account() return self.accounts.get('available', '') elif self.running_mode == 'backtest': return self.acc.cash_available def run(self): while True: time.sleep(self.risk_check_gap) self.risk_check()
class QAStrategyStockBase(QAStrategyCTABase): def __init__(self, code=['000001'], frequence='1min', strategy_id='QA_STRATEGY', risk_check_gap=1, portfolio='default', start='2019-01-01', end='2019-10-21', send_wx=False, market_type='stock_cn', data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=None, mongo_ip=mongo_ip): super().__init__(code=code, frequence=frequence, strategy_id=strategy_id, risk_check_gap=risk_check_gap, portfolio=portfolio, start=start, end=end, send_wx=send_wx, data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=taskid, mongo_ip=mongo_ip) self.code = code self.send_wx = send_wx self.dtcode = {} stock_pool_pd = pd.read_csv( "/root/qa_strategy/stock_strategy/stock_pool.csv", encoding='utf-8', converters={'code': str}) self.stock_pool_list = stock_pool_pd['code'].tolist() ''' ''' print('订阅远程行情开始:') self.subscriber = subscriber_topic(host='www.yutiansut.com', port='5678', exchange='QARealtimePro_FIX', durable=False, vhost='/', routing_key='*') #pymongo.MongoClient(mongo_ip).qa.drop_collection('REALTIMEPRO_FIX') self.db = pymongo.MongoClient(mongo_ip).qa.REALTIMEPRO_FIX def subscribe_data(self, code, frequence, data_host, data_port, data_user, data_password): """[summary] Arguments: code {[type]} -- [description] frequence {[type]} -- [description] """ self.sub = subscriber_topic( exchange='realtime_stock_{}'.format(frequence), host=data_host, port=data_port, user=data_user, password=data_password, routing_key='') for item in code: self.sub.add_sub(exchange='realtime_stock_{}'.format(frequence), routing_key=item) self.sub.callback = self.callback self.subscriber.callback = self.callback def getSimStock(self, codes, frequence): code_list = [] for code in codes: if (code.startswith('3') or code.startswith('0')): code_list.append('SZ' + str(code)) elif (code.startswith('6')): code_list.append('SH' + str(code)) cursor = self.db.find( { 'code': { '$in': code_list }, "datetime": { "$gte": str(datetime.date.today()), "$lte": str(datetime.datetime.now()) }, 'frequence': frequence }, {"_id": 0}, batch_size=10000) new_list = [] for item in cursor: new_list.append(self.format_stock_data(item)) res = pd.DataFrame([item for item in new_list]) try: # res['datetime'] = pd.to_datetime(res['datetime']) print(res) res = res.query('volume>1').drop_duplicates([ 'datetime', 'code' ]).set_index(['datetime', 'code' ]).loc[:, ['open', 'high', 'low', 'close', 'volume']] except: res = None return res def upcoming_data(self, new_bar): """upcoming_bar : Arguments: new_bar {json} -- [description] """ self._market_data = pd.concat([self._old_data.tail(200), new_bar]) # QA.QA_util_log_info(self._market_data) if self.isupdate: self.update() self.isupdate = False self.update_account() # self.positions.on_price_change(float(new_bar['close'])) #print('new_bar...',new_bar) self.on_bar(new_bar) def ind2str(self, ind, ind_type): z = ind.tail(1).reset_index().to_dict(orient='records')[0] return json.dumps({ 'topic': ind_type, 'code': self.code, 'type': self.frequence, 'data': z }) def callback(self, a, b, c, body): """在strategy的callback中,我们需要的是 1. 更新数据 2. 更新bar 3. 更新策略状态 4. 推送事件 Arguments: a {[type]} -- [description] b {[type]} -- [description] c {[type]} -- [description] body {[type]} -- [description] """ #print(body) new_data = json.loads(str(body, encoding='utf-8')) self.newbar(new_data) def newbar(self, new_data): for item in new_data: new_dict = self.format_stock_data(item) self.new_data = new_dict # 只接受5min if (not self.new_data or self.new_data['type'] != '5min'): # print('new_data 不存在', new_data) continue self.running_time = self.new_data['datetime'] code = self.new_data['code'] if code not in self.dtcode or self.dtcode[code] != str( self.new_data['datetime'])[0:16]: # [0:16]是分钟线位数 print('update!!!!!!!!!!!! dt:') self.dtcode[code] = str(self.new_data['datetime'])[0:16] self.isupdate = True self.latest_price[self.new_data['code']] = self.new_data['close'] self.acc.on_price_change(self.new_data['code'], self.new_data['close']) bar = pd.DataFrame([self.new_data]).set_index(['datetime', 'code']) #bar = QA_DataStruct_Stock_min(bar) bar = bar.loc[:, ['open', 'high', 'low', 'close', 'volume']] #print('bar:.......',bar) self.upcoming_data(bar) def format_stock_data(self, item): code = item.get('code') new_code = code[-6:] d = {} #and item.get('frequence') == '1min' if new_code in self.stock_pool_list: d['code'] = new_code d['open'] = item.get('open') d['high'] = item.get('high') d['close'] = item.get('close') d['low'] = item.get('low') d['vol'] = item.get('volume') d['volume'] = item.get('volume') d['type'] = item.get('frequence') # d['amount'] = item.get('volume') d['date_stamp'] = QA_util_date_stamp(item.get('datetime')) d['time_stamp'] = QA_util_time_stamp(item.get('datetime')) d['date'] = item.get('datetime')[0:10] # 2020-10-12 d['datetime'] = pd.to_datetime( item.get('datetime')) # 2020-10-12 10:02:00 d['tradetime'] = item.get('datetime')[0:16] # 2020-10-12 10:02 return d def _debug_sim(self): self.running_mode = 'sim' self._old_data = QA.QA_fetch_stock_min( self.code, QA.QA_util_get_last_day( QA.QA_util_get_real_date(str(datetime.date.today())), 5), str(datetime.datetime.now()), format='pd', frequence=self.frequence).set_index(['datetime', 'code']) print('old:', self._old_data) #当天启动前行情数据 sim_stock_df = self.getSimStock(self.code, self.frequence) self._old_data = pd.concat([self._old_data, sim_stock_df]) self._old_data = self._old_data.loc[:, [ 'open', 'high', 'low', 'close', 'volume' ]] #print('old_data ;:::::::', self._old_data) self.database = pymongo.MongoClient(mongo_ip).QAREALTIME self.client = self.database.account self.subscriber_client = self.database.subscribe self.acc = QIFI_Account(username=self.strategy_id, password=self.strategy_id, trade_host=mongo_ip) print(self.acc) self.acc.initial() self.pub = publisher_routing(exchange='QAORDER_ROUTER', host=self.trade_host, port=self.trade_port, user=self.trade_user, password=self.trade_password) self.subscribe_data(self.code, self.frequence, self.data_host, self.data_port, self.data_user, self.data_password) self.database.strategy_schedule.job_control.update( {'strategy_id': self.strategy_id}, { 'strategy_id': self.strategy_id, 'taskid': self.taskid, 'filepath': os.path.abspath(__file__), 'status': 200 }, upsert=True) # threading.Thread(target=, daemon=True).start() # print(self.subscribe_data) # self.sub.start() #self.debug_callback() self.subscriber.start() def debug_callback(self): new_data = [{ 'datetime': '2021-01-27 18:05:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000338', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0 }] self.newbar(new_data) # 另一个code new_data = [{ 'datetime': '2021-01-27 18:05:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000545', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0 }] self.newbar(new_data) new_data = [{ 'datetime': '2021-01-27 18:10:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000338', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0 }] self.newbar(new_data) new_data = [{ 'datetime': '2021-01-27 18:10:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000545', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0 }] self.newbar(new_data) new_data = [{ 'datetime': '2021-01-27 18:15:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000338', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0 }] self.newbar(new_data) new_data = [{ 'datetime': '2021-01-27 18:15:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000545', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0 }] self.newbar(new_data) ''' new_data = [{'datetime': '2021-01-27 18:15:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000338','open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0}] self.newbar(new_data) new_data = [{'datetime': '2021-01-27 18:15:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000545', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0}] self.newbar(new_data) new_data = [{'datetime': '2021-01-27 18:20:00', 'updatetime': '2021-01-15 10:10:51', 'code': 'SZ000338', 'open': 5.24, 'high': 5.24, 'low': 5.24, 'close': 5.24, 'volume': 39378.0, 'frequence': '5min', 'pctchange': 0.0}] self.newbar(new_data) ''' def run(self): while True: pass def debug(self): self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.acc = port.new_accountpro(account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type) # self.positions = self.acc.get_position(self.code) print('data') data = QA.QA_quotation(self.code, self.start, self.end, source=QA.DATASOURCE.MONGO, frequence=self.frequence, market=self.market_type, output=QA.OUTPUT_FORMAT.DATASTRUCT) print(data.data) data.data.apply(self.x1, axis=1) def update_account(self): if self.running_mode == 'sim': QA.QA_util_log_info('{} UPDATE ACCOUNT'.format( str(datetime.datetime.now()))) self.accounts = self.acc.account_msg self.orders = self.acc.orders self.positions = self.acc.positions self.trades = self.acc.trades self.updatetime = self.acc.dtstr elif self.running_mode == 'backtest': # self.positions = self.acc.get_position(self.code) self.positions = self.acc.positions def send_order( self, direction='BUY', offset='OPEN', code=None, price=3925, volume=10, order_id='', ): towards = eval('ORDER_DIRECTION.{}_{}'.format(direction, offset)) order_id = str(uuid.uuid4()) if order_id == '' else order_id if self.market_type == QA.MARKET_TYPE.STOCK_CN: """ 在此对于股票的部分做一些转换 """ if towards == ORDER_DIRECTION.SELL_CLOSE: towards = ORDER_DIRECTION.SELL elif towards == ORDER_DIRECTION.BUY_OPEN: towards = ORDER_DIRECTION.BUY if isinstance(price, float): pass elif isinstance(price, pd.Series): price = price.values[0] if self.running_mode == 'sim': QA.QA_util_log_info( '============ {} SEND ORDER =================='.format( order_id)) QA.QA_util_log_info( 'direction{} offset {} price{} volume{}'.format( direction, offset, price, volume)) if self.check_order(direction, offset): self.last_order_towards = {'BUY': '', 'SELL': ''} self.last_order_towards[direction] = offset now = str(datetime.datetime.now()) order = self.acc.send_order(code=code, towards=towards, price=price, amount=volume, order_id=order_id) order['topic'] = 'send_order' self.pub.pub(json.dumps(order), routing_key=self.strategy_id) self.acc.make_deal(order) self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id if self.send_wx: for user in self.subscriber_list: QA.QA_util_log_info(self.subscriber_list) try: "oL-C4w2WlfyZ1vHSAHLXb2gvqiMI" """http://www.yutiansut.com/signal?user_id=oL-C4w1HjuPRqTIRcZUyYR0QcLzo&template=xiadan_report&\ strategy_id=test1&realaccount=133496&code=rb1910&order_direction=BUY&\ order_offset=OPEN&price=3600&volume=1&order_time=20190909 """ requests.post( 'http://www.yutiansut.com/signal?user_id={}&template={}&strategy_id={}&realaccount={}&code={}&order_direction={}&order_offset={}&price={}&volume={}&order_time={}' .format(user, "xiadan_report", self.strategy_id, self.acc.user_id, code, direction, offset, price, volume, now)) except Exception as e: QA.QA_util_log_info(e) else: QA.QA_util_log_info('failed in ORDER_CHECK') elif self.running_mode == 'backtest': self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id self.acc.receive_simpledeal(code=code, trade_time=self.running_time, trade_towards=towards, trade_amount=volume, trade_price=price, order_id=order_id)
class QAStrategyCTABase(): def __init__(self, code='rb1905', frequence='1min', strategy_id='QA_STRATEGY', risk_check_gap=1, portfolio='default', start='2019-01-01', end='2019-10-21', init_cash=1000000, send_wx=False, data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=None, mongo_ip=mongo_ip): self.trade_host = trade_host self.code = code self.frequence = frequence self.strategy_id = strategy_id self.portfolio = portfolio self.data_host = data_host self.data_port = data_port self.data_user = data_user self.data_password = data_password self.trade_host = trade_host self.trade_port = trade_port self.trade_user = trade_user self.trade_password = trade_password self.start = start self.end = end self.init_cash = init_cash self.taskid = taskid self.running_time = '' self.market_preset = QA.QAARP.MARKET_PRESET() self._market_data = [] self.risk_check_gap = risk_check_gap self.isupdate = False self.new_data = {} self._systemvar = {} self._signal = [] self.send_wx = send_wx self.last_order_towards = {'BUY': '', 'SELL': ''} self.dt = '' if isinstance(self.code, str): self.market_type = MARKET_TYPE.FUTURE_CN if re.search( r'[a-zA-z]+', self.code) else MARKET_TYPE.STOCK_CN else: self.market_type = MARKET_TYPE.FUTURE_CN if re.search( r'[a-zA-z]+', self.code[0]) else MARKET_TYPE.STOCK_CN self.bar_order = { 'BUY_OPEN': 0, 'SELL_OPEN': 0, 'BUY_CLOSE': 0, 'SELL_CLOSE': 0 } @property def bar_id(self): return len(self._market_data) def _debug_sim(self): self.running_mode = 'sim' if self.frequence.endswith('min'): self._old_data = QA.QA_fetch_get_future_min( 'tdx', self.code.upper(), QA.QA_util_get_last_day( QA.QA_util_get_real_date(str(datetime.date.today()))), str(datetime.datetime.now()), self.frequence)[:-1].set_index(['datetime', 'code']) self._old_data = self._old_data.assign( volume=self._old_data.trade ).loc[:, ['open', 'high', 'low', 'close', 'volume']] else: pass self.database = pymongo.MongoClient(mongo_ip).QAREALTIME self.client = self.database.account self.subscriber_client = self.database.subscribe self.acc = QIFI_Account(username=self.strategy_id, password=self.strategy_id, trade_host=mongo_ip, init_cash=self.init_cash) self.acc.initial() self.pub = publisher_routing(exchange='QAORDER_ROUTER', host=self.trade_host, port=self.trade_port, user=self.trade_user, password=self.trade_password) self.subscribe_data(self.code.lower(), self.frequence, self.data_host, self.data_port, self.data_user, self.data_password) self.database.strategy_schedule.job_control.update( {'strategy_id': self.strategy_id}, { 'strategy_id': self.strategy_id, 'taskid': self.taskid, 'filepath': os.path.abspath(__file__), 'status': 200 }, upsert=True) def debug_sim(self): self._debug_sim() threading.Thread(target=self.sub.start, daemon=True).start() def run_sim(self): self._debug_sim() self.sub.start() def run_backtest(self): self.debug() self.acc.save() risk = QA_Risk(self.acc) risk.save() try: """add rank flow if exist QARank是我们内部用于评价策略ELO的库 此处并不影响正常使用 """ from QARank import QA_Rank QA_Rank(self.acc).send() except: pass def debug(self): self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.acc = port.new_accountpro(account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type) self.positions = self.acc.get_position(self.code) print(self.acc) print(self.acc.market_type) data = QA.QA_quotation(self.code.upper(), self.start, self.end, source=QA.DATASOURCE.MONGO, frequence=self.frequence, market=self.market_type, output=QA.OUTPUT_FORMAT.DATASTRUCT) def x1(item): # print(data) if str(item.name[0])[0:10] != str(self.running_time)[0:10]: self.on_dailyclose() self.on_dailyopen() if self.market_type == QA.MARKET_TYPE.STOCK_CN: print('backtest: Settle!') self.acc.settle() self._on_1min_bar() self._market_data.append(item) self.running_time = str(item.name[0]) self.on_bar(item) data.data.apply(x1, axis=1) def subscribe_data(self, code, frequence, data_host, data_port, data_user, data_password): """[summary] Arguments: code {[type]} -- [description] frequence {[type]} -- [description] """ self.sub = subscriber(exchange='realtime_{}_{}'.format( frequence, code), host=data_host, port=data_port, user=data_user, password=data_password) self.sub.callback = self.callback def subscribe_multi(self, codelist, frequence, data_host, data_port, data_user, data_password): self.sub = subscriber_topic(exchange='realtime_{}'.format(frequence), host=data_host, port=data_port, user=data_user, password=data_password) for item in codelist: self.sub.add_sub(exchange='realtime_{}'.format(frequence), routing_key=item) self.sub.callback = self.callback @property def old_data(self): return self._old_data def update(self): """ 此处是切换bar的时候的节点 """ self._old_data = self._market_data self._on_1min_bar() @property def market_datetime(self): return self.market_data.index.levels[0] @property def market_data(self): if self.running_mode == 'sim': return self._market_data elif self.running_mode == 'backtest': return pd.concat(self._market_data[-100:], axis=1, sort=False).T def force_close(self): # 强平 if self.positions.volume_long > 0: self.send_order('SELL', 'CLOSE', price=self.positions.last_price, volume=self.positions.volume_long) if self.positions.volume_short > 0: self.send_order('BUY', 'CLOSE', price=self.positions.last_price, volume=self.positions.volume_short) def upcoming_data(self, new_bar): """upcoming_bar : Arguments: new_bar {json} -- [description] """ self._market_data = pd.concat([self._old_data, new_bar]) # QA.QA_util_log_info(self._market_data) if self.isupdate: self.update() self.isupdate = False self.update_account() self.positions.on_price_change(float(self.new_data['close'])) self.on_bar(self.new_data) def ind2str(self, ind, ind_type): z = ind.tail(1).reset_index().to_dict(orient='records')[0] return json.dumps({ 'topic': ind_type, 'code': self.code, 'type': self.frequence, 'data': z }) def callback(self, a, b, c, body): """在strategy的callback中,我们需要的是 1. 更新数据 2. 更新bar 3. 更新策略状态 4. 推送事件 Arguments: a {[type]} -- [description] b {[type]} -- [description] c {[type]} -- [description] body {[type]} -- [description] """ self.new_data = json.loads(str(body, encoding='utf-8')) if self.dt != str(self.new_data['datetime'])[0:16]: print('update!!!!!!!!!!!!') self.dt = str(self.new_data['datetime'])[0:16] self.isupdate = True self.acc.on_price_change(self.code, self.new_data['close']) # .loc[:, ['open', 'high', 'low', 'close', 'volume', 'tradetime']] bar = pd.DataFrame([self.new_data]).set_index(['datetime', 'code']) now = datetime.datetime.now() if now.hour == 20 and now.minute == 59 and now.second < 10: self.daily_func() time.sleep(10) # res = self.job_control.find_one( # {'strategy_id': self.strategy_id, 'strategy_id': self.strategy_id}) # self.control_status(res) self.running_time = self.new_data['datetime'] self.upcoming_data(bar) def control_status(self, res): print(res) def add_subscriber(self, qaproid): """Add a subscriber 增加订阅者的QAPRO_ID """ self.subscriber_client.insert_one({ 'strategy_id': self.strategy_id, 'user_id': qaproid }) @property def subscriber_list(self): """订阅者 Returns: [type] -- [description] """ return list( set([ item['user_id'] for item in self.subscriber_client.find( {'strategy_id': self.strategy_id}) ])) def load_strategy(self): raise NotImplementedError def on_dailyopen(self): pass def on_dailyclose(self): pass def on_bar(self, bar): raise NotImplementedError def _on_1min_bar(self): #raise NotImplementedError if len(self._systemvar.keys()) > 0: self._signal.append(copy.deepcopy(self._systemvar)) def on_1min_bar(self): raise NotImplementedError def on_5min_bar(self): raise NotImplementedError def on_15min_bar(self): raise NotImplementedError def on_30min_bar(self): raise NotImplementedError def order_handler(self): self._orders = {} def daily_func(self): QA.QA_util_log_info('DAILY FUNC') def risk_check(self): pass def plot(self, name, data, format): """ plot是可以存储你的临时信息的接口, 后期会接入可视化 Arguments: name {[type]} -- [description] data {[type]} -- [description] format {[type]} -- [description] """ self._systemvar[name] = { 'datetime': copy.deepcopy(str(self.running_time)), 'value': data, 'format': format } def check_order(self, direction, offset): """[summary] 同方向不开仓 只对期货市场做限制 buy - open sell - close """ if self.market_type == QA.MARKET_TYPE.FUTURE_CN: if self.last_order_towards[direction] == str(offset): return False else: return True else: return True def receive_simpledeal(self, code: str, trade_time, trade_amount, direction, offset, trade_price, message='sell_open'): self.send_order(direction=direction, offset=offset, volume=trade_amount, price=trade_price, order_id=QA.QA_util_random_with_topic( self.strategy_id)) def send_order( self, direction='BUY', offset='OPEN', price=3925, volume=10, order_id='', ): towards = eval('ORDER_DIRECTION.{}_{}'.format(direction, offset)) order_id = str(uuid.uuid4()) if order_id == '' else order_id if isinstance(price, float): pass elif isinstance(price, pd.Series): price = price.values[0] if self.running_mode == 'sim': QA.QA_util_log_info( '============ {} SEND ORDER =================='.format( order_id)) QA.QA_util_log_info( 'direction{} offset {} price{} volume{}'.format( direction, offset, price, volume)) if self.check_order(direction, offset): self.last_order_towards = {'BUY': '', 'SELL': ''} self.last_order_towards[direction] = offset now = str(datetime.datetime.now()) order = self.acc.send_order(code=self.code, towards=towards, price=price, amount=volume, order_id=order_id) order['topic'] = 'send_order' self.pub.pub(json.dumps(order), routing_key=self.strategy_id) self.acc.make_deal(order) self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id if self.send_wx: for user in self.subscriber_list: QA.QA_util_log_info(self.subscriber_list) try: "oL-C4w2WlfyZ1vHSAHLXb2gvqiMI" """http://www.yutiansut.com/signal?user_id=oL-C4w1HjuPRqTIRcZUyYR0QcLzo&template=xiadan_report&\ strategy_id=test1&realaccount=133496&code=rb1910&order_direction=BUY&\ order_offset=OPEN&price=3600&volume=1&order_time=20190909 """ requests.post( 'http://www.yutiansut.com/signal?user_id={}&template={}&strategy_id={}&realaccount={}&code={}&order_direction={}&order_offset={}&price={}&volume={}&order_time={}' .format(user, "xiadan_report", self.strategy_id, self.acc.user_id, self.code.lower(), direction, offset, price, volume, now)) except Exception as e: QA.QA_util_log_info(e) else: QA.QA_util_log_info('failed in ORDER_CHECK') elif self.running_mode == 'backtest': self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id self.acc.receive_simpledeal(code=self.code, trade_time=self.running_time, trade_towards=towards, trade_amount=volume, trade_price=price, order_id=order_id) self.positions = self.acc.get_position(self.code) def update_account(self): if self.running_mode == 'sim': QA.QA_util_log_info('{} UPDATE ACCOUNT'.format( str(datetime.datetime.now()))) self.accounts = self.acc.account_msg self.orders = self.acc.orders self.positions = self.acc.get_position(self.code) self.trades = self.acc.trades self.updatetime = self.acc.dtstr elif self.running_mode == 'backtest': self.positions = self.acc.get_position(self.code) def get_exchange(self, code): return self.market_preset.get_exchange(code) def get_positions(self, code): if self.running_mode == 'sim': self.update_account() return self.positions elif self.running_mode == 'backtest': return self.acc.get_position(code) def get_cash(self): if self.running_mode == 'sim': self.update_account() return self.accounts.get('available', '') elif self.running_mode == 'backtest': return self.acc.cash_available def run(self): while True: time.sleep(self.risk_check_gap) self.risk_check()
class QAStrategyCoinBase(QAStrategyCTABase): def __init__(self, code=['000001'], frequence='1min', strategy_id='QA_STRATEGY', risk_check_gap=1, portfolio='default', start='2019-01-01', end='2019-10-21', send_wx=False, market_type='stock_cn', data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=None, mongo_ip=mongo_ip): super().__init__(code=code, frequence=frequence, strategy_id=strategy_id, risk_check_gap=risk_check_gap, portfolio=portfolio, start=start, end=end, send_wx=send_wx, data_host=eventmq_ip, data_port=eventmq_port, data_user=eventmq_username, data_password=eventmq_password, trade_host=eventmq_ip, trade_port=eventmq_port, trade_user=eventmq_username, trade_password=eventmq_password, taskid=taskid, mongo_ip=mongo_ip) self.code = code self.dtcode = {} self.send_wx = send_wx self.frequenceInt = 0 ''' self.subscriber = subscriber_topic( host='www.yutiansut.com', port='5678', exchange='QARealtimePro_FIX', durable=False, vhost='/', routing_key='*') ''' def subscribe_data(self, code, frequence, data_host, data_port, data_user, data_password): """[summary] Arguments: code {[type]} -- [description] frequence {[type]} -- [description] """ self.sub = subscriber_topic(exchange='realtime_stock_{}'.format( frequence), host=data_host, port=data_port, user=data_user, password=data_password, routing_key='') for item in code: self.sub.add_sub(exchange='realtime_stock_{}'.format( frequence), routing_key=item) self.sub.callback = self.callback self.subscriber.callback = self.callback def upcoming_data(self, new_bar): """upcoming_bar : Arguments: new_bar {json} -- [description] """ self._market_data = pd.concat([self._old_data, new_bar]) # QA.QA_util_log_info(self._market_data) if self.isupdate: self.update() self.isupdate = False self.update_account() # self.positions.on_price_change(float(new_bar['close'])) self.on_bar(new_bar) def ind2str(self, ind, ind_type): z = ind.tail(1).reset_index().to_dict(orient='records')[0] return json.dumps({'topic': ind_type, 'code': self.code, 'type': self.frequence, 'data': z}) def callback(self, a, b, c, body): """在strategy的callback中,我们需要的是 1. 更新数据 2. 更新bar 3. 更新策略状态 4. 推送事件 Arguments: a {[type]} -- [description] b {[type]} -- [description] c {[type]} -- [description] body {[type]} -- [description] """ print(time.strftime("%H:%M:%S", time.localtime())) while True: time_now_min = int(time.strftime("%M", time.localtime())) time_now_s = int(time.strftime("%S", time.localtime())) frequence_int = self.frequenceInt if (time_now_min%frequence_int == 0 and (time_now_s%30 == 0 or time_now_s%59 == 0)) : time.sleep(1) # 延迟1s 防止上边的if重复执行 QA.QA_util_log_info('{} while开始....'.format( str(datetime.datetime.now()))) code_list = [huobi_SYMBOL.format(x) for x in self.code] # new_data = json.loads(str(body, encoding='utf-8')) lastPreMinTime = (datetime.datetime.now()).strftime( "%Y-%m-%d %H:%M:%S") preLastPreMinTime = (datetime.datetime.now() + datetime.timedelta(minutes=-4 * frequence_int)).strftime( "%Y-%m-%d %H:%M:%S") print(preLastPreMinTime, lastPreMinTime, self.frequence) self._new_data = QA.QA_fetch_cryptocurrency_min(code_list, preLastPreMinTime, lastPreMinTime, format='pd', frequence=self.frequence) if (self._new_data.empty): continue self._new_data = self._new_data.loc[:, ['code','open', 'high', 'low', 'close', 'volume','datetime']] #self._market_data.iloc[-1:] print('NEW DATA:', self._new_data) #整理成一个code的一个frequence为一个bar for idx, row in self._new_data.iterrows(): #print("当前row:",row) code = row['code'] self.latest_price[row['code']] = code self.running_time = row['datetime'] #if self.dt != str(row['datetime'])[0:16]: if code not in self.dtcode or self.dtcode[code] < str(row['datetime'])[0:16]: # [0:16]是分钟线位数 print('update!!!!!!!!!!!!') self.dtcode[code] = str(row['datetime'])[0:16] self.isupdate = True self.acc.on_price_change(code, row['close']) bar = pd.DataFrame([row]).set_index(['datetime', 'code']).loc[:, ['open', 'high', 'low', 'close', 'volume']] #print(bar) self.upcoming_data(bar) def format_stock_data(self, item): code = item.get('code') new_code = code[-6:] d = {} #print(new_code) #print(item) import pandas as pd stock_pool_pd = pd.read_csv("/root/sim/stock_strategy/stock_pool.csv",encoding='utf-8',converters = {'code':str}); stock_pool_list = stock_pool_pd['code'].tolist() if new_code in stock_pool_list and item.get('frequence') == '5min': d['code'] = new_code d['open'] = item.get('open') d['high'] = item.get('high') d['close'] = item.get('close') d['low'] = item.get('low') d['vol'] = item.get('volume') d['type'] = item.get('frequence') #d['amount'] = item.get('volume') d['date_stamp'] = QA_util_date_stamp(item.get('datetime')) d['time_stamp'] = QA_util_time_stamp(item.get('datetime')) d['date'] = item.get('datetime')[0:10] #2020-10-12 d['datetime'] = item.get('datetime') #2020-10-12 10:02:00 d['tradetime'] = item.get('datetime')[0:16] #2020-10-12 10:02 return d def _debug_sim(self): self.running_mode = 'sim' QA_SU_save_huobi_min(frequency= self.frequence, fetch_range= self.code) frequence_int = int(re.findall("\d+", self.frequence)[0]) self.frequenceInt = frequence_int start = (datetime.datetime.now() + datetime.timedelta(minutes=-500 * frequence_int)).strftime( "%Y-%m-%d %H:%M:%S") end = (datetime.datetime.now() + datetime.timedelta(minutes=-frequence_int)).strftime( "%Y-%m-%d %H:%M:%S") code_list = self.code self._old_data = QA.QA_fetch_stock_min(code_list, start, end, format='pd', frequence=self.frequence).set_index(['datetime', 'code']) #print(self._old_data) self._old_data = self._old_data.loc[:, ['open', 'high', 'low', 'close', 'volume']] self.database = pymongo.MongoClient(mongo_ip).QAREALTIME self.client = self.database.account self.subscriber_client = self.database.subscribe self.acc = QIFI_Account( username=self.strategy_id, password=self.strategy_id, trade_host=mongo_ip) self.acc.initial() self.pub = publisher_routing(exchange='QAORDER_ROUTER', host=self.trade_host, port=self.trade_port, user=self.trade_user, password=self.trade_password) ''' self.subscribe_data(self.code, self.frequence, self.data_host, self.data_port, self.data_user, self.data_password) ''' self.database.strategy_schedule.job_control.update( {'strategy_id': self.strategy_id}, {'strategy_id': self.strategy_id, 'taskid': self.taskid, 'filepath': os.path.abspath(__file__), 'status': 200}, upsert=True) # threading.Thread(target=, daemon=True).start() #print(self.subscribe_data) #self.sub.start() #self.subscriber.start() self.callback(1,2,3,4) def run(self): while True: pass def debug(self): self.running_mode = 'backtest' self.database = pymongo.MongoClient(mongo_ip).QUANTAXIS user = QA_User(username="******", password='******') port = user.new_portfolio(self.portfolio) self.acc = port.new_accountpro( account_cookie=self.strategy_id, init_cash=self.init_cash, market_type=self.market_type) #self.positions = self.acc.get_position(self.code) data = QA.QA_quotation(self.code, self.start, self.end, source=QA.DATASOURCE.MONGO, frequence=self.frequence, market=self.market_type, output=QA.OUTPUT_FORMAT.DATASTRUCT) #print(data.data) data.data.apply(self.x1, axis=1) def update_account(self): if self.running_mode == 'sim': QA.QA_util_log_info('{} UPDATE ACCOUNT'.format( str(datetime.datetime.now()))) self.accounts = self.acc.account_msg self.orders = self.acc.orders self.positions = self.acc.positions self.trades = self.acc.trades self.updatetime = self.acc.dtstr elif self.running_mode == 'backtest': #self.positions = self.acc.get_position(self.code) self.positions = self.acc.positions def send_order(self, direction='BUY', offset='OPEN', code=None, price=3925, volume=10, order_id='',): towards = eval('ORDER_DIRECTION.{}_{}'.format(direction, offset)) order_id = str(uuid.uuid4()) if order_id == '' else order_id if self.market_type == QA.MARKET_TYPE.STOCK_CN: """ 在此对于股票的部分做一些转换 """ if towards == ORDER_DIRECTION.SELL_CLOSE: towards = ORDER_DIRECTION.SELL elif towards == ORDER_DIRECTION.BUY_OPEN: towards = ORDER_DIRECTION.BUY if isinstance(price, float): pass elif isinstance(price, pd.Series): price = price.values[0] if self.running_mode == 'sim': QA.QA_util_log_info( '============ {} SEND ORDER =================='.format(order_id)) QA.QA_util_log_info('direction{} offset {} price{} volume{}'.format( direction, offset, price, volume)) if self.check_order(direction, offset, code): self.last_order_towards = {'BUY': '', 'SELL': ''} self.last_order_towards[direction] = offset now = str(datetime.datetime.now()) order = self.acc.send_order( code=code, towards=towards, price=price, amount=volume, order_id=order_id) order['topic'] = 'send_order' self.pub.pub( json.dumps(order), routing_key=self.strategy_id) self.acc.make_deal(order) self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id if self.send_wx: for user in self.subscriber_list: QA.QA_util_log_info(self.subscriber_list) try: "oL-C4w2WlfyZ1vHSAHLXb2gvqiMI" """http://www.yutiansut.com/signal?user_id=oL-C4w1HjuPRqTIRcZUyYR0QcLzo&template=xiadan_report&\ strategy_id=test1&realaccount=133496&code=rb1910&order_direction=BUY&\ order_offset=OPEN&price=3600&volume=1&order_time=20190909 """ requests.post('http://www.yutiansut.com/signal?user_id={}&template={}&strategy_id={}&realaccount={}&code={}&order_direction={}&order_offset={}&price={}&volume={}&order_time={}'.format( user, "xiadan_report", self.strategy_id, self.acc.user_id, code, direction, offset, price, volume, now)) except Exception as e: QA.QA_util_log_info(e) else: QA.QA_util_log_info('failed in ORDER_CHECK') elif self.running_mode == 'backtest': self.bar_order['{}_{}'.format(direction, offset)] = self.bar_id self.acc.receive_simpledeal( code=code, trade_time=self.running_time, trade_towards=towards, trade_amount=volume, trade_price=price, order_id=order_id)