def __init__(self, if_start_orderthreading=True, *args, **kwargs): """[summary] Keyword Arguments: if_start_orderthreading {bool} -- 是否在初始化的时候开启查询子线程(实盘需要) (default: {False}) @2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 """ super().__init__() # 以下是待初始化的账户session self.session = {} # 以下都是官方支持的交易前置 self._broker = { BROKER_TYPE.BACKETEST: QA_BacktestBroker, BROKER_TYPE.RANODM: QA_RandomBroker, BROKER_TYPE.REAL: QA_RealBroker, BROKER_TYPE.SIMULATION: QA_SimulatedBroker, BROKER_TYPE.SHIPANE: QA_SPEBroker } self.broker = {} self.running_time = None self.last_query_data = None self.if_start_orderthreading = if_start_orderthreading self.order_handler = QA_OrderHandler()
def __init__(self, auto_logon=True): super().__init__() self.name = BROKER_TYPE.TTS self.config = TTSConfig() self.order_handler = QA_OrderHandler() self._endpoint = 'http://%s:%s/api' % ( self.config.values['trade_server_ip'], self.config.values['trade_server_port']) self._encoding = "utf-8" if self.config.values['transport_enc_key'] == '' or self.config.values[ 'transport_enc_iv'] == '': self._transport_enc = False self._transport_enc_key = None self._transport_enc_iv = None self._cipher = None else: self._transport_enc = True self._transport_enc_key = bytes( self.config.values['transport_enc_key'], encoding=self._encoding) self._transport_enc_iv = bytes( self.config.values['transport_enc_iv'], encoding=self._encoding) self._cipher = Cipher(algorithms.AES(self._transport_enc_key), modes.CBC(self._transport_enc_iv), backend=default_backend()) self._session = requests.Session() self.client_id = 0 self.gddm_sh = 0 # 上海股东代码 self.gddm_sz = 0 # 深圳股东代码 if auto_logon is True: self.logon()
def __init__(self, if_nondatabase=False): """[summary] Keyword Arguments: commission_fee_coeff {[type]} -- [description] (default: {0}) environment {[type]} -- [description] (default: {RUNNING_ENVIRONMENT}) if_nondatabase {[type]} -- [description] (default: {False}) """ super().__init__() self.dealer = QA_Dealer() self.order_handler = QA_OrderHandler() self.engine = { MARKET_TYPE.STOCK_CN: self.dealer.backtest_stock_dealer} self.fetcher = {(MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min} self.market_data = None self.if_nondatabase = if_nondatabase self.name = BROKER_TYPE.BACKETEST self._quotation = {} # 一个可以缓存数据的dict self.broker_data = None self.deal_message = {}
def __init__(self, if_start_orderthreading=True, *args, **kwargs): """MARKET的初始化过程 Market的初始属性: session: MARKET的账户字典 _broker: 当前所有的broker集合 TODO: 转移到QAParameter broker: MARKET的broker字典 running_time: MARKET当前的运行时间 last_query_data: MARKET上次获取的数据 if_start_orderthreading: MARKET是否开启订单队列线程的开关 order_handler: 订单队列 Keyword Arguments: if_start_orderthreading {bool} -- 是否在初始化的时候开启查询子线程(实盘需要) (default: {False}) @2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 """ super().__init__() # 以下是待初始化的账户session self.session = {} # 以下都是官方支持的交易前置 self._broker = { BROKER_TYPE.BACKETEST: QA_BacktestBroker, BROKER_TYPE.RANDOM: QA_RandomBroker, BROKER_TYPE.REAL: QA_RealBroker, BROKER_TYPE.SIMULATION: QA_SimulatedBroker, BROKER_TYPE.SHIPANE: QA_SPEBroker, BROKER_TYPE.TTS: QA_TTSBroker, } self.broker = {} self.running_time = None self.last_query_data = None self.if_start_orderthreading = if_start_orderthreading self.order_handler = QA_OrderHandler()
def __init__(self): super().__init__() self.name = BROKER_TYPE.SHIPANE self.order_handler = QA_OrderHandler() self.setting = get_config_SPE() self._session = requests self._endpoint = self.setting.uri self.key = self.setting.key
def __init__(self, endpoint="http://127.0.0.1:10092/api", encoding="utf-8", enc_key=None, enc_iv=None): super().__init__() self.name = BROKER_TYPE.TTS self.order_handler = QA_OrderHandler() self._endpoint = endpoint self._encoding = "utf-8" if enc_key == None or enc_iv == None: self._transport_enc = False self._transport_enc_key = None self._transport_enc_iv = None self._cipher = None else: self._transport_enc = True self._transport_enc_key = enc_key self._transport_enc_iv = enc_iv backend = default_backend() self._cipher = Cipher(algorithms.AES(enc_key), modes.CBC(enc_iv), backend=backend) self._session = requests.Session() self.client_id = 0 self.gddm_sh = 0 #上海股东代码 self.gddm_sz = 0 #深圳股东代码 self.fetcher = { (MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_get_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min }
def __init__(self): self.order_handler = QA_OrderHandler() self.setting = get_config_SPE() self._session = requests self._endpoint = self.setting.uri self.key = self.setting.key #self.account_headers = ['forzen_cash','balance_available','cash_available','pnl_money_today','total_assets','pnl_holding','market_value','money_available'] self.fillorder_headers = ['name', 'datetime', 'towards', 'price', 'amount', 'money', 'trade_id', 'order_id', 'code', 'shareholder', 'other'] self.holding_headers = ['code', 'name', 'hoding_price', 'price', 'pnl', 'amount', 'sell_available', 'pnl_money', 'holdings', 'total_amount', 'lastest_amounts', 'shareholder'] self.askorder_headers = ['code', 'towards', 'price', 'amount', 'transaction_price', 'transaction_amount', 'status', 'order_time', 'order_id', 'id', 'code', 'shareholders']
def __init__(self,if_nondatabase=False): """[summary] Keyword Arguments: commission_fee_coeff {[type]} -- [description] (default: {0}) environment {[type]} -- [description] (default: {RUNNING_ENVIRONMENT}) if_nondatabase {[type]} -- [description] (default: {False}) """ super().__init__() self.dealer = QA_Dealer() self.order_handler = QA_OrderHandler() self.engine = { MARKET_TYPE.STOCK_CN: self.dealer.backtest_stock_dealer} self.fetcher = {(MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min} self.market_data = None self.if_nondatabase = if_nondatabase self.name = BROKER_TYPE.BACKETEST self._quotation = {} # 一个可以缓存数据的dict self.broker_data = None
def __init__(self, auto_logon=True): super().__init__() self.name = BROKER_TYPE.TTS self.config = TTSConfig() self.order_handler = QA_OrderHandler() self._endpoint = 'http://%s:%s/api' % ( self.config.values['trade_server_ip'], self.config.values['trade_server_port']) self._encoding = "utf-8" if self.config.values['transport_enc_key'] == '' or self.config.values['transport_enc_iv'] == '': self._transport_enc = False self._transport_enc_key = None self._transport_enc_iv = None self._cipher = None else: self._transport_enc = True self._transport_enc_key = bytes( self.config.values['transport_enc_key'], encoding=self._encoding) self._transport_enc_iv = bytes( self.config.values['transport_enc_iv'], encoding=self._encoding) self._cipher = Cipher( algorithms.AES(self._transport_enc_key), modes.CBC(self._transport_enc_iv), backend=default_backend()) self._session = requests.Session() self.client_id = 0 self.gddm_sh = 0 # 上海股东代码 self.gddm_sz = 0 # 深圳股东代码 if auto_logon is True: self.logon()
def __init__(self, if_start_orderthreading=True, *args, **kwargs): """MARKET的初始化过程 Keyword Arguments: if_start_orderthreading {bool} -- 是否在初始化的时候开启查询子线程(实盘需要) (default: {False}) @2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 """ super().__init__() # 以下是待初始化的账户session self.session = {} # 以下都是官方支持的交易前置 self._broker = { BROKER_TYPE.BACKETEST: QA_BacktestBroker, BROKER_TYPE.RANDOM: QA_RandomBroker, BROKER_TYPE.REAL: QA_RealBroker, BROKER_TYPE.SIMULATION: QA_SimulatedBroker, BROKER_TYPE.SHIPANE: QA_SPEBroker, BROKER_TYPE.TTS: QA_TTSBroker, } self.broker = {} self.running_time = None self.last_query_data = None self.if_start_orderthreading = if_start_orderthreading self.order_handler = QA_OrderHandler()
def start_order_threading(self): """开启查询子线程(实盘中用) """ self.if_start_orderthreading = True self.order_handler = QA_OrderHandler() self.trade_engine.create_kernel('ORDER') self.trade_engine.start_kernel('ORDER')
def __init__(self, endpoint="http://127.0.0.1:10092/api", encoding="utf-8", enc_key=None, enc_iv=None): super().__init__() self.name = BROKER_TYPE.TTS self.order_handler = QA_OrderHandler() self._endpoint = endpoint self._encoding = "utf-8" if enc_key == None or enc_iv == None: self._transport_enc = False self._transport_enc_key = None self._transport_enc_iv = None self._cipher = None else: self._transport_enc = True self._transport_enc_key = enc_key self._transport_enc_iv = enc_iv backend = default_backend() self._cipher = Cipher(algorithms.AES(enc_key), modes.CBC(enc_iv), backend=backend) self._session = requests.Session() self.client_id = 0 self.gddm_sh = 0 #上海股东代码 self.gddm_sz = 0 #深圳股东代码 self.fetcher = { (MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_get_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min } #通过代码前缀区分market_type self.code_table = { '000': { 'type': 'stock', 'market': 'SZ' }, '001': { 'type': 'stock', 'market': 'SZ' }, '002': { 'type': 'stock', 'market': 'SZ' }, '150': { 'type': 'fj', 'market': 'SZ' }, '159': { 'type': 'etf', 'market': 'SZ' }, '161': { 'type': 'etf', 'market': 'SZ' }, '163': { 'type': 'etf', 'market': 'SZ' }, '164': { 'type': 'etf', 'market': 'SZ' }, '168': { 'type': 'etf', 'market': 'SZ' }, '169': { 'type': 'etf', 'market': 'SZ' }, '300': { 'type': 'stock', 'market': 'SZ' }, '501': { 'type': 'etf', 'market': 'SH' }, '502': { 'type': 'fj', 'market': 'SH' }, '510': { 'type': 'etf', 'market': 'SH' }, '511': { 'type': 'etf', 'market': 'SH' }, '512': { 'type': 'etf', 'market': 'SH' }, '513': { 'type': 'etf', 'market': 'SH' }, '518': { 'type': 'etf', 'market': 'SH' }, '600': { 'type': 'stock', 'market': 'SH' }, '601': { 'type': 'stock', 'market': 'SH' }, '603': { 'type': 'stock', 'market': 'SH' }, }
class QA_TTSBroker(QA_Broker): fetcher = {(MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_get_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min} def __init__(self, auto_logon=True): super().__init__() self.name = BROKER_TYPE.TTS self.config = TTSConfig() self.order_handler = QA_OrderHandler() self._endpoint = 'http://%s:%s/api' % ( self.config.values['trade_server_ip'], self.config.values['trade_server_port']) self._encoding = "utf-8" if self.config.values['transport_enc_key'] == '' or self.config.values['transport_enc_iv'] == '': self._transport_enc = False self._transport_enc_key = None self._transport_enc_iv = None self._cipher = None else: self._transport_enc = True self._transport_enc_key = bytes( self.config.values['transport_enc_key'], encoding=self._encoding) self._transport_enc_iv = bytes( self.config.values['transport_enc_iv'], encoding=self._encoding) self._cipher = Cipher( algorithms.AES(self._transport_enc_key), modes.CBC(self._transport_enc_iv), backend=default_backend()) self._session = requests.Session() self.client_id = 0 self.gddm_sh = 0 # 上海股东代码 self.gddm_sz = 0 # 深圳股东代码 if auto_logon is True: self.logon() def call(self, func, params=None): json_obj = { "func": func } if params is not None: json_obj["params"] = params if self._transport_enc: data_to_send = self.encrypt(json_obj) response = self._session.post(self._endpoint, data=data_to_send) else: response = self._session.post(self._endpoint, json=json_obj) response.encoding = self._encoding text = response.text if self._transport_enc: decoded_text = self.decrypt(text) # print(decoded_text) return json.loads(decoded_text) else: return json.loads(text) def encrypt(self, source_obj): encrypter = self._cipher.encryptor() source = json.dumps(source_obj) source = source.encode(self._encoding) need_to_padding = 16 - (len(source) % 16) if need_to_padding > 0: source = source + b'\x00' * need_to_padding enc_data = encrypter.update(source) + encrypter.finalize() b64_enc_data = base64.encodebytes(enc_data) return urllib.parse.quote(b64_enc_data) def decrypt(self, source): decrypter = self._cipher.decryptor() source = urllib.parse.unquote(source) source = base64.decodebytes(source.encode("utf-8")) data_bytes = decrypter.update(source) + decrypter.finalize() return data_bytes.rstrip(b"\x00").decode(self._encoding) def data_to_df(self, result): if 'data' in result: data = result['data'] df = pd.DataFrame(data=data) df.rename( columns=lambda x: cn_en_compare[x] if x in cn_en_compare else x, inplace=True) if hasattr(df, 'towards'): df.towards = df.towards.apply( lambda x: trade_towards_cn_en[x] if x in trade_towards_cn_en else x) if hasattr(df, 'status'): df.status = df.status.apply( lambda x: order_status_cn_en[x] if x in order_status_cn_en else x) if hasattr(df, 'order_time'): df.order_time = df.order_time.apply( lambda x: '{} {}'.format( datetime.date.today().strftime('%Y-%m-%d'), datetime.datetime.strptime(x, '%H%M%S').strftime('%H:%M:%S'))) if hasattr(df, 'trade_time'): df.trade_time = df.trade_time.apply( lambda x: '{} {}'.format( datetime.date.today().strftime('%Y-%m-%d'), datetime.datetime.strptime(x, '%H%M%S').strftime('%H:%M:%S'))) if hasattr(df, 'realorder_id'): df.realorder_id = df.realorder_id.apply(str) if hasattr(df, 'amount'): df.amount = df.amount.apply(pd.to_numeric) if hasattr(df, 'price'): df.price = df.price.apply(pd.to_numeric) if hasattr(df, 'money'): df.money = df.money.apply(pd.to_numeric) if hasattr(df, 'trade_amount'): df.trade_amount = df.trade_amount.apply(pd.to_numeric) if hasattr(df, 'trade_price'): df.trade_price = df.trade_price.apply(pd.to_numeric) if hasattr(df, 'trade_money'): df.trade_money = df.trade_money.apply(pd.to_numeric) if hasattr(df, 'order_price'): df.order_price = df.order_price.apply(pd.to_numeric) if hasattr(df, 'order_amount'): df.order_amount = df.order_amount.apply(pd.to_numeric) if hasattr(df, 'order_money'): df.order_money = df.order_money.apply(pd.to_numeric) if hasattr(df, 'cancel_amount'): df.cancel_amount = df.cancel_amount.apply(pd.to_numeric) return df else: return pd.DataFrame() #------ functions def ping(self): return self.call("ping", {}) def logon(self): data = self.call("logon", { "ip": self.config.values['tdx_server_ip'], "port": int(self.config.values['tdx_server_port']), "version": self.config.values['tdx_version'], "yyb_id": int(self.config.values['user_yyb']), "account_no": self.config.values['user_name'], "trade_account": self.config.values['user_name'], "jy_password": self.config.values['user_pass'], "tx_password": self.config.values['user_tx_pass'] }) if data['success']: self.client_id = data["data"]["client_id"] self.gddm_sh = self.query_data(5)['data'][0]['股东代码'] self.gddm_sz = self.query_data(5)['data'][1]['股东代码'] print('上海股东代码:%s,深圳股东代码:%s', self.gddm_sh, self.gddm_sz) return data def logoff(self): return self.call("logoff", { "client_id": self.client_id }) def query_data(self, category): return self.call("query_data", { "client_id": self.client_id, "category": category }) def send_order(self, code, price, amount, towards, order_model, market=None): """下单 Arguments: code {[type]} -- [description] price {[type]} -- [description] amount {[type]} -- [description] towards {[type]} -- [description] order_model {[type]} -- [description] market:市场,SZ 深交所,SH 上交所 Returns: [type] -- [description] """ towards = 0 if towards == ORDER_DIRECTION.BUY else 1 if order_model == ORDER_MODEL.MARKET: order_model = 4 elif order_model == ORDER_MODEL.LIMIT: order_model = 0 if market is None: market = QAFetch.base.get_stock_market(code) if not isinstance(market, str): raise Exception('%s不正确,请检查code和market参数' % market) market = market.lower() if market not in ['sh', 'sz']: raise Exception('%s不支持,请检查code和market参数' % market) return self.data_to_df(self.call("send_order", { 'client_id': self.client_id, 'category': towards, 'price_type': order_model, 'gddm': self.gddm_sh if market == 'sh' else self.gddm_sz, 'zqdm': code, 'price': price, 'quantity': amount })) def cancel_order(self, exchange_id, order_id): """ Arguments: exchange_id {[type]} -- 交易所 0 深圳 1上海 (偶尔2是深圳) order_id {[type]} -- [description] Returns: [type] -- [description] """ return self.call("cancel_order", { 'client_id': self.client_id, 'exchange_id': exchange_id, 'hth': order_id }) def get_quote(self, code): return self.call("get_quote", { 'client_id': self.client_id, 'code': code, }) def repay(self, amount): return self.call("repay", { 'client_id': self.client_id, 'amount': amount }) def receive_order(self, event): res = self.send_order(code=event.order.code, price=event.order.price, amount=event.order.amount, towards=event.order.towards, order_model=event.order.order_model) try: event.order.queued(res.realorder_id[0]) print('success receive order {}'.format(event.order.realorder_id)) except Exception as e: print(res.realorder_id[0]) print(event.order) print(e) event.order.failed() print( 'FAILED FOR CREATE ORDER {} {}'.format( event.order.account_cookie, event.order.status ) ) return event.order def run(self, event): # if event.event_type is MARKET_EVENT.QUERY_DATA: # self.order_handler.run(event) # try: # data = self.fetcher[(event.market_type, event.frequence)]( # code=event.code, start=event.start, end=event.end).values[0] # if 'vol' in data.keys() and 'volume' not in data.keys(): # data['volume'] = data['vol'] # elif 'vol' not in data.keys() and 'volume' in data.keys(): # data['vol'] = data['volume'] # return data # except Exception as e: # QA_util_log_info('MARKET_ENGING ERROR: {}'.format(e)) # return None # elif event.event_type is BROKER_EVENT.RECEIVE_ORDER: # self.order_handler.run(event) # elif event.event_type is BROKER_EVENT.TRADE: # event = self.order_handler.run(event) # event.message = 'trade' # if event.callback: # event.callback(event) # el if event.event_type is MARKET_EVENT.QUERY_ORDER: self.order_handler.run(event) elif event.event_type is BROKER_EVENT.SETTLE: self.order_handler.run(event) if event.callback: event.callback('settle') def get_market(self, order): try: data = self.fetcher[(order.market_type, order.frequence)]( code=order.code, start=order.datetime, end=order.datetime).values[0] if 'vol' in data.keys() and 'volume' not in data.keys(): data['volume'] = data['vol'] elif 'vol' not in data.keys() and 'volume' in data.keys(): data['vol'] = data['volume'] return data except Exception as e: QA_util_log_info('MARKET_ENGING ERROR: {}'.format(e)) return None def query_orders(self, account_cookie, status='filled'): df = self.data_to_df(self.query_data(3 if status is 'filled' else 2)) df['account_cookie'] = account_cookie if status is 'filled': df = df[self.dealstatus_headers] if len( df) > 0 else pd.DataFrame(columns=self.dealstatus_headers) else: df['cancel_amount'] = 0 df = df[self.orderstatus_headers] if len( df) > 0 else pd.DataFrame(columns=self.orderstatus_headers) return df.set_index(['account_cookie', 'realorder_id']).sort_index() def query_positions(self, account_cookie): data = { 'cash_available': 0.00, 'hold_available': {}, } try: result = self.query_data(0) if 'data' in result and len(result['data']) > 0: # 使用减法避免因为账户日内现金理财导致可用金额错误 data['cash_available'] = round( float(result['data'][0]['总资产']) - float(result['data'][0]['最新市值']) - float( result['data'][0]['冻结资金']), 2) result = self.data_to_df(self.query_data(1)) if len(result) > 0: result.index = result.code if hasattr(result, 'amount'): data['hold_available'] = result.amount return data except: print(e) return data
class QA_SPEBroker(QA_Broker): """ 1. 查询账户: 如果有该账户, 返回可用资金和持仓 如果当前market不存在或异常, 返回False 2. 查询所有订单: 如果成功 返回一个DataFrame 如果失败 返回False 3. 查询未成交订单 如果成功 返回DataFrame 如果失败 返回False 4. 查询已成交订单 如果成功 返回DataFramne 如果失败 返回False 5. 下单 receive_order/send_order receive_order(QAMARKET 用法): 输入一个QA_ORDER类 如果下单成功 返回带realorder_id, ORDER_STATUS.QUEUED状态值 的QA_Order 如果下单失败 返回带 ORDER_STATUS.FAILED状态值的 QA_Order send_order(测试用法) 6. 撤单 cancel_order 如果撤单成功 返回 True 如果撤单失败 返回 具体的原因 dict/json格式 7. 全撤 如果成功 返回True """ def __init__(self): super().__init__() self.name = BROKER_TYPE.SHIPANE self.order_handler = QA_OrderHandler() self.setting = get_config_SPE() self._session = requests self._endpoint = self.setting.uri self.key = self.setting.key #self.account_headers = ['forzen_cash','balance_available','cash_available','pnl_money_today','total_assets','pnl_holding','market_value','money_available'] def run(self, event): if event.event_type is BROKER_EVENT.RECEIVE_ORDER: self.order_handler.run(event) #self.run(QA_Event(event_type=BROKER_EVENT.TRADE, broker=self)) # elif event.event_type is BROKER_EVENT.TRADE: # """实盘交易部分!!!!! ATTENTION # 这里需要开一个子线程去查询是否成交 # ATTENTION # """ # event = self.order_handler.run(event) # event.message = 'trade' # if event.callback: # event.callback(event) elif event.event_type is BROKER_EVENT.SETTLE: self.order_handler.run(event) if event.callback: event.callback('settle') def call(self, func, params=''): try: if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client')) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client')) # print(uri) response = self._session.get(uri, params) text = response.text return json.loads(text) except Exception as e: #print(e) if isinstance(e,ConnectionRefusedError): print('与主机失去连接') print(e) else: print(e) # print(uri) return None def call_post(self, func, params={}): if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client')) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client')) response = self._session.post(uri, json=params) text = response.text return json.loads(text) def call_delete(self, func, params=''): if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client')) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client')) response = self._session.delete(uri) text = response.text # print(text) try: if text in ['', '获取提示对话框超时,因为:组件为空']: print('success') return True else: return json.loads(text) except: return text def data_to_df(self, result): return pd.DataFrame(data=result) #------ functions def ping(self): return self.call("ping", {}) def query_accounts(self, accounts): return self.call("accounts", { 'client': accounts }) def query_positions(self, accounts): """查询现金和持仓 Arguments: accounts {[type]} -- [description] Returns: dict-- {'cash':xxx,'position':xxx} """ try: data = self.call("positions", { 'client': accounts }) #print(data) if data is not None: cash_part = data.get('subAccounts', {}).get('人民币', False) if cash_part: cash_available = cash_part.get('可用金额') position_part = data.get('dataTable', False) if position_part: res = data.get('dataTable', False) if res: hold_headers = res['columns'] hold_headers = [cn_en_compare[item] for item in hold_headers] hold_available = pd.DataFrame( res['rows'], columns=hold_headers) return {'cash_available': cash_available, 'hold_available': hold_available.assign(amount=hold_available.amount.apply(float)).loc[:, ['code', 'amount']].set_index('code').amount} else: print(data) return False, 'None ACCOUNT' except: return False def query_clients(self): return self.call("clients") def query_orders(self, accounts, status='filled'): """查询订单 Arguments: accounts {[type]} -- [description] Keyword Arguments: status {str} -- 'open' 待成交 'filled' 成交 (default: {'filled'}) Returns: [type] -- [description] """ try: data = self.call("orders", { 'client': accounts, 'status': status }) if data is not None: orders = data.get('dataTable', False) order_headers = orders['columns'] order_headers = [cn_en_compare[item] for item in order_headers] order_all = pd.DataFrame( orders['rows'], columns=order_headers).assign(account_cookie=accounts) order_all.towards = order_all.towards.apply( lambda x: trade_towards_cn_en[x]) if 'order_time' in order_headers: # 这是order_status order_all.status = order_all.status.apply(lambda x: order_status_cn_en[x]) if 'order_date' not in order_headers: order_all.order_time = order_all.order_time.apply( lambda x: QA_util_get_order_datetime(dt='{} {}'.format(datetime.date.today(), x))) else: order_all = order_all.assign(order_time=order_all.order_date.apply(QA_util_date_int2str)+' '+order_all.order_time) if 'trade_time' in order_headers: order_all.trade_time = order_all.trade_time.apply( lambda x: '{} {}'.format(datetime.date.today(), x)) if status is 'filled': return order_all.loc[:, self.dealstatus_headers].set_index(['account_cookie', 'realorder_id']).sort_index() else: return order_all.loc[:, self.orderstatus_headers].set_index(['account_cookie', 'realorder_id']).sort_index() else: print('response is None') return False except Exception as e: print(e) return False def send_order(self, accounts, code='000001', price=9, amount=100, order_direction=ORDER_DIRECTION.BUY, order_model=ORDER_MODEL.LIMIT): """[summary] Arguments: accounts {[type]} -- [description] code {[type]} -- [description] price {[type]} -- [description] amount {[type]} -- [description] Keyword Arguments: order_direction {[type]} -- [description] (default: {ORDER_DIRECTION.BUY}) order_model {[type]} -- [description] (default: {ORDER_MODEL.LIMIT}) priceType 可选择: 上海交易所: 0 - 限价委托 4 - 五档即时成交剩余撤销 6 - 五档即时成交剩余转限 深圳交易所: 0 - 限价委托 1 - 对手方最优价格委托 2 - 本方最优价格委托 3 - 即时成交剩余撤销委托 4 - 五档即时成交剩余撤销 5 - 全额成交或撤销委托 Returns: [type] -- [description] """ try: #print(code, price, amount) return self.call_post('orders', { 'client': accounts, "action": 'BUY' if order_direction == 1 else 'SELL', "symbol": code, "type": order_model, "priceType": 0 if order_model == ORDER_MODEL.LIMIT else 4, "price": price, "amount": amount }) except json.decoder.JSONDecodeError: print(RuntimeError('TRADE ERROR')) return None def cancel_order(self, accounts, orderid): return self.call_delete('orders/{}'.format(orderid), { 'client': accounts }) def cancel_all(self, accounts): return self.call_delete('orders', { 'client': accounts }) def receive_order(self, event): order = event.order res = self.send_order(accounts=order.account_cookie, code=order.code, price=order.price, amount=order.amount, order_direction=order.towards, order_model=order.order_model) try: # if res is not None and 'id' in res.keys(): # order.status = ORDER_STATUS.QUEUED # order.text = 'SUCCESS' order.queued(realorder_id=res['id']) print('success receive order {}'.format(order.realorder_id)) return order # else: except: text = 'WRONG' if res is None else res.get( 'message', 'WRONG') order.failed(text) print('FAILED FOR CREATE ORDER {} {}'.format( order.account_cookie, order.status)) print(res) return order
class QA_TTSBroker(QA_Broker): fetcher = { (MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_get_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_get_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_get_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_get_index_min } def __init__(self, auto_logon=True): super().__init__() self.name = BROKER_TYPE.TTS self.config = TTSConfig() self.order_handler = QA_OrderHandler() self._endpoint = 'http://%s:%s/api' % ( self.config.values['trade_server_ip'], self.config.values['trade_server_port']) self._encoding = "utf-8" if self.config.values['transport_enc_key'] == '' or self.config.values[ 'transport_enc_iv'] == '': self._transport_enc = False self._transport_enc_key = None self._transport_enc_iv = None self._cipher = None else: self._transport_enc = True self._transport_enc_key = bytes( self.config.values['transport_enc_key'], encoding=self._encoding) self._transport_enc_iv = bytes( self.config.values['transport_enc_iv'], encoding=self._encoding) self._cipher = Cipher(algorithms.AES(self._transport_enc_key), modes.CBC(self._transport_enc_iv), backend=default_backend()) self._session = requests.Session() self.client_id = 0 self.gddm_sh = 0 # 上海股东代码 self.gddm_sz = 0 # 深圳股东代码 if auto_logon is True: self.logon() def call(self, func, params=None): json_obj = {"func": func} if params is not None: json_obj["params"] = params if self._transport_enc: data_to_send = self.encrypt(json_obj) response = self._session.post(self._endpoint, data=data_to_send) else: response = self._session.post(self._endpoint, json=json_obj) response.encoding = self._encoding text = response.text if self._transport_enc: decoded_text = self.decrypt(text) # print(decoded_text) return json.loads(decoded_text) else: return json.loads(text) def encrypt(self, source_obj): encrypter = self._cipher.encryptor() source = json.dumps(source_obj) source = source.encode(self._encoding) need_to_padding = 16 - (len(source) % 16) if need_to_padding > 0: source = source + b'\x00' * need_to_padding enc_data = encrypter.update(source) + encrypter.finalize() b64_enc_data = base64.encodebytes(enc_data) return urllib.parse.quote(b64_enc_data) def decrypt(self, source): decrypter = self._cipher.decryptor() source = urllib.parse.unquote(source) source = base64.decodebytes(source.encode("utf-8")) data_bytes = decrypter.update(source) + decrypter.finalize() return data_bytes.rstrip(b"\x00").decode(self._encoding) def data_to_df(self, result): if 'data' in result: data = result['data'] df = pd.DataFrame(data=data) df.rename(columns=lambda x: cn_en_compare[x] if x in cn_en_compare else x, inplace=True) if hasattr(df, 'towards'): df.towards = df.towards.apply(lambda x: trade_towards_cn_en[ x] if x in trade_towards_cn_en else x) if hasattr(df, 'status'): df.status = df.status.apply(lambda x: order_status_cn_en[x] if x in order_status_cn_en else x) if hasattr(df, 'order_time'): df.order_time = df.order_time.apply(lambda x: '{} {}'.format( datetime.date.today().strftime('%Y-%m-%d'), datetime.datetime.strptime(x, '%H%M%S').strftime('%H:%M:%S' ))) if hasattr(df, 'trade_time'): df.trade_time = df.trade_time.apply(lambda x: '{} {}'.format( datetime.date.today().strftime('%Y-%m-%d'), datetime.datetime.strptime(x, '%H%M%S').strftime('%H:%M:%S' ))) if hasattr(df, 'amount'): df.amount = df.amount.apply(pd.to_numeric) if hasattr(df, 'price'): df.price = df.price.apply(pd.to_numeric) if hasattr(df, 'money'): df.money = df.money.apply(pd.to_numeric) if hasattr(df, 'trade_amount'): df.trade_amount = df.trade_amount.apply(pd.to_numeric) if hasattr(df, 'trade_price'): df.trade_price = df.trade_price.apply(pd.to_numeric) if hasattr(df, 'trade_money'): df.trade_money = df.trade_money.apply(pd.to_numeric) if hasattr(df, 'order_price'): df.order_price = df.order_price.apply(pd.to_numeric) if hasattr(df, 'order_amount'): df.order_amount = df.order_amount.apply(pd.to_numeric) if hasattr(df, 'order_money'): df.order_money = df.order_money.apply(pd.to_numeric) if hasattr(df, 'cancel_amount'): df.cancel_amount = df.cancel_amount.apply(pd.to_numeric) return df else: return pd.DataFrame() #------ functions def ping(self): return self.call("ping", {}) def logon(self): data = self.call( "logon", { "ip": self.config.values['tdx_server_ip'], "port": int(self.config.values['tdx_server_port']), "version": self.config.values['tdx_version'], "yyb_id": int(self.config.values['user_yyb']), "account_no": self.config.values['user_name'], "trade_account": self.config.values['user_name'], "jy_password": self.config.values['user_pass'], "tx_password": self.config.values['user_tx_pass'] }) if data['success']: self.client_id = data["data"]["client_id"] self.gddm_sh = self.query_data(5)['data'][0]['股东代码'] self.gddm_sz = self.query_data(5)['data'][1]['股东代码'] print('上海股东代码:%s,深圳股东代码:%s', self.gddm_sh, self.gddm_sz) return data def logoff(self): return self.call("logoff", {"client_id": self.client_id}) def query_data(self, category): return self.call("query_data", { "client_id": self.client_id, "category": category }) def send_order(self, code, price, amount, towards, order_model, market=None): """下单 Arguments: code {[type]} -- [description] price {[type]} -- [description] amount {[type]} -- [description] towards {[type]} -- [description] order_model {[type]} -- [description] market:市场,SZ 深交所,SH 上交所 Returns: [type] -- [description] """ towards = 0 if towards == ORDER_DIRECTION.BUY else 1 if order_model == ORDER_MODEL.MARKET: order_model = 4 elif order_model == ORDER_MODEL.LIMIT: order_model = 0 if market is None: market = QAFetch.base.get_stock_market(code) if not isinstance(market, str): raise Exception('%s不正确,请检查code和market参数' % market) market = market.lower() if market not in ['sh', 'sz']: raise Exception('%s不支持,请检查code和market参数' % market) return self.data_to_df( self.call( "send_order", { 'client_id': self.client_id, 'category': towards, 'price_type': order_model, 'gddm': self.gddm_sh if market == 'sh' else self.gddm_sz, 'zqdm': code, 'price': price, 'quantity': amount })) def cancel_order(self, exchange_id, order_id): """ Arguments: exchange_id {[type]} -- 交易所 0 深圳 1上海 (偶尔2是深圳) order_id {[type]} -- [description] Returns: [type] -- [description] """ return self.call( "cancel_order", { 'client_id': self.client_id, 'exchange_id': exchange_id, 'hth': order_id }) def get_quote(self, code): return self.call("get_quote", { 'client_id': self.client_id, 'code': code, }) def repay(self, amount): return self.call("repay", { 'client_id': self.client_id, 'amount': amount }) def receive_order(self, event): res = self.send_order(code=event.order.code, price=event.order.price, amount=event.order.amount, towards=event.order.towards, order_model=event.order.order_model) try: event.order.queued(realorder_id=res.realorder_id[0]) print('success receive order {}'.format(event.order.realorder_id)) except: event.order.failed() print('FAILED FOR CREATE ORDER {} {}'.format( event.order.account_cookie, event.order.status)) return event.order def run(self, event): # if event.event_type is MARKET_EVENT.QUERY_DATA: # self.order_handler.run(event) # try: # data = self.fetcher[(event.market_type, event.frequence)]( # code=event.code, start=event.start, end=event.end).values[0] # if 'vol' in data.keys() and 'volume' not in data.keys(): # data['volume'] = data['vol'] # elif 'vol' not in data.keys() and 'volume' in data.keys(): # data['vol'] = data['volume'] # return data # except Exception as e: # QA_util_log_info('MARKET_ENGING ERROR: {}'.format(e)) # return None # elif event.event_type is BROKER_EVENT.RECEIVE_ORDER: # self.order_handler.run(event) # elif event.event_type is BROKER_EVENT.TRADE: # event = self.order_handler.run(event) # event.message = 'trade' # if event.callback: # event.callback(event) # el if event.event_type is MARKET_EVENT.QUERY_ORDER: self.order_handler.run(event) elif event.event_type is BROKER_EVENT.SETTLE: self.order_handler.run(event) if event.callback: event.callback('settle') def get_market(self, order): try: data = self.fetcher[(order.market_type, order.frequence)]( code=order.code, start=order.datetime, end=order.datetime).values[0] if 'vol' in data.keys() and 'volume' not in data.keys(): data['volume'] = data['vol'] elif 'vol' not in data.keys() and 'volume' in data.keys(): data['vol'] = data['volume'] return data except Exception as e: QA_util_log_info('MARKET_ENGING ERROR: {}'.format(e)) return None def query_orders(self, account_cookie, status='filled'): df = self.data_to_df(self.query_data(3 if status is 'filled' else 2)) df['account_cookie'] = account_cookie if status is 'filled': df = df[self.dealstatus_headers] if len(df) > 0 else pd.DataFrame( columns=self.dealstatus_headers) else: df['cancel_amount'] = 0 df = df[self.orderstatus_headers] if len(df) > 0 else pd.DataFrame( columns=self.orderstatus_headers) return df.set_index(['account_cookie', 'realorder_id']).sort_index() def query_positions(self, account_cookie): data = { 'cash_available': 0.00, 'hold_available': {}, } try: result = self.query_data(0) if 'data' in result and len(result['data']) > 0: # 使用减法避免因为账户日内现金理财导致可用金额错误 data['cash_available'] = round( float(result['data'][0]['总资产']) - float(result['data'][0]['最新市值']) - float(result['data'][0]['冻结资金']), 2) result = self.data_to_df(self.query_data(1)) if len(result) > 0: result.index = result.code if hasattr(result, 'amount'): data['hold_available'] = result.amount return data except: print(e) return data
class QA_SPEBroker(QA_Broker): """ 1. 查询账户: 如果有该账户, 返回可用资金和持仓 如果当前market不存在或异常, 返回False 2. 查询所有订单: 如果成功 返回一个DataFrame 如果失败 返回False 3. 查询未成交订单 如果成功 返回DataFrame 如果失败 返回False 4. 查询已成交订单 如果成功 返回DataFramne 如果失败 返回False 5. 下单 receive_order/send_order receive_order(QAMARKET 用法): 输入一个QA_ORDER类 如果下单成功 返回带realorder_id, ORDER_STATUS.QUEUED状态值 的QA_Order 如果下单失败 返回带 ORDER_STATUS.FAILED状态值的 QA_Order send_order(测试用法) 6. 撤单 cancel_order 如果撤单成功 返回 True 如果撤单失败 返回 具体的原因 dict/json格式 7. 全撤 如果成功 返回True """ def __init__(self): super().__init__() self.name = BROKER_TYPE.SHIPANE self.order_handler = QA_OrderHandler() self.setting = get_config_SPE() self._session = requests self._endpoint = self.setting.uri self.key = self.setting.key #self.account_headers = ['forzen_cash','balance_available','cash_available','pnl_money_today','total_assets','pnl_holding','market_value','money_available'] def run(self, event): if event.event_type is BROKER_EVENT.RECEIVE_ORDER: self.order_handler.run(event) elif event.event_type is BROKER_EVENT.SETTLE: self.order_handler.run(event) if event.callback: event.callback('settle') def call(self, func, params=''): try: if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client') ) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client') ) # print(uri) response = self._session.get(uri, params) text = response.text return json.loads(text) except Exception as e: # print(e) if isinstance(e, ConnectionRefusedError): print('与主机失去连接') print(e) else: print(e) # print(uri) return None def call_post(self, func, params={}): if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client') ) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client') ) response = self._session.post(uri, json=params) text = response.text return json.loads(text) def call_delete(self, func, params=''): if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client') ) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client') ) response = self._session.delete(uri) text = response.text # print(text) try: if text in ['', '获取提示对话框超时,因为:组件为空']: print('success') return True else: return json.loads(text) except: return text def data_to_df(self, result): return pd.DataFrame(data=result) #------ functions def ping(self): return self.call("ping", {}) def query_accounts(self, accounts): return self.call("accounts", {'client': accounts}) def query_positions(self, accounts): """查询现金和持仓 Arguments: accounts {[type]} -- [description] Returns: dict-- {'cash_available':xxx,'hold_available':xxx} """ try: data = self.call("positions", {'client': accounts}) if data is not None: cash_part = data.get('subAccounts', {}).get('人民币', False) if cash_part: cash_available = cash_part.get('可用金额', cash_part.get('可用')) position_part = data.get('dataTable', False) if position_part: res = data.get('dataTable', False) if res: hold_headers = res['columns'] hold_headers = [ cn_en_compare[item] for item in hold_headers ] hold_available = pd.DataFrame( res['rows'], columns=hold_headers ) if len(hold_available) == 1 and hold_available.amount[0] in [ None, '', 0 ]: hold_available = pd.DataFrame( data=None, columns=hold_headers ) return { 'cash_available': cash_available, 'hold_available': hold_available.assign( amount=hold_available.amount.apply(float) ).loc[:, ['code', 'amount']].set_index('code').amount } else: print(data) return False, 'None ACCOUNT' except: return False def query_clients(self): """查询clients Returns: [type] -- [description] """ try: data = self.call("clients", {'client': 'None'}) if len(data) > 0: return pd.DataFrame(data).drop( ['commandLine', 'processId'], axis=1 ) else: return pd.DataFrame( None, columns=[ 'id', 'name', 'windowsTitle', 'accountInfo', 'status' ] ) except Exception as e: return False, e def query_orders(self, accounts, status='filled'): """查询订单 Arguments: accounts {[type]} -- [description] Keyword Arguments: status {str} -- 'open' 待成交 'filled' 成交 (default: {'filled'}) Returns: [type] -- [description] """ try: data = self.call("orders", {'client': accounts, 'status': status}) if data is not None: orders = data.get('dataTable', False) order_headers = orders['columns'] if ('成交状态' in order_headers or '状态说明' in order_headers) and ('备注' in order_headers): order_headers[order_headers.index('备注')] = '废弃' order_headers = [cn_en_compare[item] for item in order_headers] order_all = pd.DataFrame( orders['rows'], columns=order_headers ).assign(account_cookie=accounts) order_all.towards = order_all.towards.apply( lambda x: trade_towards_cn_en[x] ) if 'order_time' in order_headers: # 这是order_status order_all['status'] = order_all.status.apply( lambda x: order_status_cn_en[x] ) if 'order_date' not in order_headers: order_all.order_time = order_all.order_time.apply( lambda x: QA_util_get_order_datetime( dt='{} {}'.format(datetime.date.today(), x) ) ) else: order_all = order_all.assign( order_time=order_all.order_date .apply(QA_util_date_int2str) + ' ' + order_all.order_time ) if 'trade_time' in order_headers: order_all.trade_time = order_all.trade_time.apply( lambda x: '{} {}'.format(datetime.date.today(), x) ) if status is 'filled': return order_all.loc[:, self.dealstatus_headers].set_index( ['account_cookie', 'realorder_id'] ).sort_index() else: return order_all.loc[:, self.orderstatus_headers].set_index( ['account_cookie', 'realorder_id'] ).sort_index() else: print('response is None') return False except Exception as e: print(e) return False def send_order( self, accounts, code='000001', price=9, amount=100, order_direction=ORDER_DIRECTION.BUY, order_model=ORDER_MODEL.LIMIT ): """[summary] Arguments: accounts {[type]} -- [description] code {[type]} -- [description] price {[type]} -- [description] amount {[type]} -- [description] Keyword Arguments: order_direction {[type]} -- [description] (default: {ORDER_DIRECTION.BUY}) order_model {[type]} -- [description] (default: {ORDER_MODEL.LIMIT}) priceType 可选择: 上海交易所: 0 - 限价委托 4 - 五档即时成交剩余撤销 6 - 五档即时成交剩余转限 深圳交易所: 0 - 限价委托 1 - 对手方最优价格委托 2 - 本方最优价格委托 3 - 即时成交剩余撤销委托 4 - 五档即时成交剩余撤销 5 - 全额成交或撤销委托 Returns: [type] -- [description] """ try: #print(code, price, amount) return self.call_post( 'orders', { 'client': accounts, "action": 'BUY' if order_direction == 1 else 'SELL', "symbol": code, "type": order_model, "priceType": 0 if order_model == ORDER_MODEL.LIMIT else 4, "price": price, "amount": amount } ) except json.decoder.JSONDecodeError: print(RuntimeError('TRADE ERROR')) return None def cancel_order(self, accounts, orderid): return self.call_delete( 'orders/{}'.format(orderid), {'client': accounts} ) def cancel_all(self, accounts): return self.call_delete('orders', {'client': accounts}) def receive_order(self, event): order = event.order res = self.send_order( accounts=order.account_cookie, code=order.code, price=order.price, amount=order.amount, order_direction=order.towards, order_model=order.order_model ) try: # if res is not None and 'id' in res.keys(): # order.status = ORDER_STATUS.QUEUED # order.text = 'SUCCESS' order.queued(realorder_id=res['id']) print('success receive order {}'.format(order.realorder_id)) return order # else: except: text = 'WRONG' if res is None else res.get('message', 'WRONG') order.failed(text) print( 'FAILED FOR CREATE ORDER {} {}'.format( order.account_cookie, order.status ) ) print(res) return order
class QA_BacktestBroker(QA_Broker): """ QUANTAXIS Broker 部分 回测 股票/指数/期货/债券/ETF/基金 @yutiansut 对于不同的市场规则: 股票市场 t+1 期货/期权/加密货币市场 t+0 股票/加密货币市场不允许卖空 期货/期权市场允许卖空 t+1的市场是 当日的买入 更新持仓- 不更新可卖数量- 资金冻结 当日的卖出 及时更新可用资金 t+0市场是: 当日买入 即时更新持仓和可卖 当日卖出 即时更新 卖空的规则是 允许无仓位的时候卖出证券(按市值和保证金比例限制算) """ def __init__(self, if_nondatabase=False): """[summary] Keyword Arguments: commission_fee_coeff {[type]} -- [description] (default: {0}) environment {[type]} -- [description] (default: {RUNNING_ENVIRONMENT}) if_nondatabase {[type]} -- [description] (default: {False}) """ super().__init__() self.dealer = QA_Dealer() self.order_handler = QA_OrderHandler() self.fetcher = { (MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.FUTURE_CN, FREQUENCE.DAY): QA_fetch_future_day, (MARKET_TYPE.FUTURE_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_future_min, (MARKET_TYPE.FUTURE_CN, FREQUENCE.ONE_MIN): QA_fetch_future_min, (MARKET_TYPE.FUTURE_CN, FREQUENCE.FIVE_MIN): QA_fetch_future_min, (MARKET_TYPE.FUTURE_CN, FREQUENCE.THIRTY_MIN): QA_fetch_future_min, (MARKET_TYPE.FUTURE_CN, FREQUENCE.SIXTY_MIN): QA_fetch_future_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min } self.market_data = None self.if_nondatabase = if_nondatabase self.name = BROKER_TYPE.BACKETEST self._quotation = {} # 一个可以缓存数据的dict self.broker_data = None self.deal_message = {} def run(self, event): #strDbg = QA_util_random_with_topic("QABacktestBroker.run") #print(" >-----------------------QABacktestBroker.run----------------------------->", strDbg,'evt->', event) if event.event_type is MARKET_EVENT.QUERY_DATA: # 查询数据部分 code = event.code frequence = event.frequence start = event.start end = start if event.end is None else event.end market_type = event.market_type res = self.query_data(code, start, end, frequence, market_type) if event.callback: event.callback(res) else: return res elif event.event_type is MARKET_EVENT.QUERY_ORDER: self.order_handler.run(event) elif event.event_type is ENGINE_EVENT.UPCOMING_DATA: # QABacktest 回测发出的事件 new_marketdata_dict = event.market_data.dicts for item in new_marketdata_dict.keys(): if item not in self._quotation.keys(): self._quotation[item] = new_marketdata_dict[item] # if self.broker_data is None: # self.broker_data = event.market_data # else: # self.broker_data.append(event.market_data) # self.broker_data=event.market_data elif event.event_type is BROKER_EVENT.RECEIVE_ORDER: self.order_handler.run(event) #self.run(QA_Event(event_type=BROKER_EVENT.TRADE, broker=self)) elif event.event_type is BROKER_EVENT.TRADE: event = self.order_handler.run(event) event.message = 'trade' if event.callback: event.callback(event) elif event.event_type is BROKER_EVENT.SETTLE: #self.deal_message = {} # self.order_handler.run(event) if event.callback: event.callback('settle') #print(" <-----------------------QABacktestBroker.run-----------------------------<",strDbg,'evt->',event) def query_data(self, code, start, end, frequence, market_type=None): """ 标准格式是numpy """ try: return self.broker_data.select_time(start, end).select_code(code ).to_json()[0] except: return self.fetcher[(market_type, frequence)]( code, start, end, frequence=frequence, format='json' ) def receive_order(self, event): """ get the order and choice which market to trade """ order = event.order # print(event.market_data) # print(order) if 'market_data' in event.__dict__.keys(): self.market_data = self.get_market( order ) if event.market_data is None else event.market_data if isinstance(self.market_data, dict): pass elif isinstance(self.market_data, pd.DataFrame): self.market_data = QA_util_to_json_from_pandas( self.market_data )[0] elif isinstance(self.market_data, pd.core.series.Series): self.market_data = self.market_data.to_dict() elif isinstance(self.market_data, np.ndarray): data = self.market_data[0] else: # print(type(self.market_data)) self.market_data = self.market_data.to_json()[0] else: self.market_data = self.get_market(order) if self.market_data is not None: order = self.warp(order) self.dealer.deal(order, self.market_data) order.queued(order.order_id) # 模拟的order_id 和 realorder_id 一致 else: order.failed('MARKET DATA IS NONE') #raise ValueError('MARKET DATA IS NONE CANNOT TRADE') return order def query_orders(self, account, status=''): if status == '': return self.dealer.deal_df.query( 'account_cookie=="{}"'.format(account) ).loc[:, self.orderstatus_headers].set_index( ['account_cookie', 'realorder_id'] ) elif status == 'filled': return self.dealer.deal_df.query( 'account_cookie=="{}"'.format(account) ).loc[:, self.dealstatus_headers].set_index( ['account_cookie', 'realorder_id'] ) elif status == 'open': pass def query_deal(self, account): pass def warp(self, order): """对order/market的封装 [description] Arguments: order {[type]} -- [description] Returns: [type] -- [description] """ # 因为成交模式对时间的封装 if order.order_model == ORDER_MODEL.MARKET: """ 市价单模式 """ if order.frequence is FREQUENCE.DAY: # exact_time = str(datetime.datetime.strptime( # str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = order.datetime[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: order.date = str(order.datetime)[0:10] #_original_marketvalue = order.price*order.amount order.price = ( float(self.market_data.get('high')) + float(self.market_data.get('low')) ) * 0.5 elif order.order_model == ORDER_MODEL.NEXT_OPEN: # try: # order.date = QA_util_get_next_day(str(order.datetime)[0:10]) # order.datetime = '{} 09:30:00'.format(order.date) # except: # order.datetime = '{} 15:00:00'.format(order.date) # self.market_data = self.get_market(order) # if self.market_data is None: # return order # order.price = float(self.market_data["close"]) raise NotImplementedError elif order.order_model == ORDER_MODEL.CLOSE: """ 收盘价模式 """ try: order.date = order.datetime[0:10] order.datetime = '{} 15:00:00'.format(order.date) except: if len(str(order.datetime)) == 19: pass else: order.datetime = '{} 15:00:00'.format(order.date) order.price = float(self.market_data.get('close')) elif order.order_model == ORDER_MODEL.LIMIT: """ 限价单模式 """ if order.frequence is FREQUENCE.DAY: # exact_time = str(datetime.datetime.strptime( # str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = order.datetime[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: order.date = str(order.datetime)[0:10] elif order.order_model == ORDER_MODEL.STRICT: """ 严格模式 """ if order.frequence is FREQUENCE.DAY: # exact_time = str(datetime.datetime.strptime( # str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = order.datetime[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: order.date = str(order.datetime)[0:10] if order.towards == 1: order.price = float(self.market_data.get('high')) else: order.price = float(self.market_data.get('low')) if order.market_type == MARKET_TYPE.STOCK_CN: if order.towards == ORDER_DIRECTION.BUY: if order.order_model == AMOUNT_MODEL.BY_MONEY: amount = order.money / \ (order.price*(1+order.commission_coeff)) money = order.money else: amount = order.amount money = order.amount * order.price * \ (1+order.commission_coeff) order.amount = int(amount / 100) * 100 order.money = money elif order.towards == ORDER_DIRECTION.SELL: if order.order_model == AMOUNT_MODEL.BY_MONEY: amount = order.money / \ (order.price*(1+order.commission_coeff+order.tax_coeff)) money = order.money else: amount = order.amount money = order.amount * order.price * \ (1+order.commission_coeff+order.tax_coeff) order.amount = amount order.money = money return order def get_market(self, order): """get_market func [description] Arguments: order {orders} -- [description] Returns: [type] -- [description] """ # 首先判断是否在_quotation里面 if (pd.Timestamp(order.datetime), order.code) in self._quotation.keys(): return self._quotation[(pd.Timestamp(order.datetime), order.code)] else: try: data = self.fetcher[(order.market_type, order.frequence)]( code=order.code, start=order.datetime, end=order.datetime, format='json', frequence=order.frequence )[0] if 'vol' in data.keys() and 'volume' not in data.keys(): data['volume'] = data['vol'] elif 'vol' not in data.keys() and 'volume' in data.keys(): data['vol'] = data['volume'] return data except Exception as e: QA_util_log_info('MARKET_ENGING ERROR: {}'.format(e)) return None
class QA_BacktestBroker(QA_Broker): """ QUANTAXIS Broker 部分 回测 股票/指数/期货/债券/ETF/基金 @yutiansut 对于不同的市场规则: 股票市场 t+1 期货/期权/加密货币市场 t+0 股票/加密货币市场不允许卖空 期货/期权市场允许卖空 t+1的市场是 当日的买入 更新持仓- 不更新可卖数量- 资金冻结 当日的卖出 及时更新可用资金 t+0市场是: 当日买入 即时更新持仓和可卖 当日卖出 即时更新 卖空的规则是 允许无仓位的时候卖出证券(按市值和保证金比例限制算) """ def __init__(self,if_nondatabase=False): """[summary] Keyword Arguments: commission_fee_coeff {[type]} -- [description] (default: {0}) environment {[type]} -- [description] (default: {RUNNING_ENVIRONMENT}) if_nondatabase {[type]} -- [description] (default: {False}) """ super().__init__() self.dealer = QA_Dealer() self.order_handler = QA_OrderHandler() self.engine = { MARKET_TYPE.STOCK_CN: self.dealer.backtest_stock_dealer} self.fetcher = {(MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min} self.market_data = None self.if_nondatabase = if_nondatabase self.name = BROKER_TYPE.BACKETEST self._quotation = {} # 一个可以缓存数据的dict self.broker_data = None def run(self, event): #strDbg = QA_util_random_with_topic("QABacktestBroker.run") #print(" >-----------------------QABacktestBroker.run----------------------------->", strDbg,'evt->', event) if event.event_type is MARKET_EVENT.QUERY_DATA: # 查询数据部分 code = event.code frequence = event.frequence start = event.start end = start if event.end is None else event.end market_type = event.market_type res = self.query_data(code, start, end, frequence, market_type) if event.callback: event.callback(res) else: return res elif event.event_type is MARKET_EVENT.QUERY_ORDER: self.order_handler.run(event) elif event.event_type is ENGINE_EVENT.UPCOMING_DATA: # QABacktest 回测发出的事件 new_marketdata_dict = event.market_data.dicts for item in new_marketdata_dict.keys(): if item not in self._quotation.keys(): self._quotation[item] = new_marketdata_dict[item] # if self.broker_data is None: # self.broker_data = event.market_data # else: # self.broker_data.append(event.market_data) # self.broker_data=event.market_data elif event.event_type is BROKER_EVENT.RECEIVE_ORDER: self.order_handler.run(event) self.run(QA_Event(event_type=BROKER_EVENT.TRADE, broker=self)) elif event.event_type is BROKER_EVENT.TRADE: event = self.order_handler.run(event) event.message = 'trade' if event.callback: event.callback(event) elif event.event_type is BROKER_EVENT.SETTLE: self.order_handler.run(event) if event.callback: event.callback('settle') #print(" <-----------------------QABacktestBroker.run-----------------------------<",strDbg,'evt->',event) def query_data(self, code, start, end, frequence, market_type=None): """ 标准格式是numpy """ try: return self.broker_data.select_time( start, end).select_code(code).to_numpy() except: return self.fetcher[(market_type, frequence)]( code, start, end, frequence=frequence) def receive_order(self, event): """ get the order and choice which market to trade """ order = event.order if 'market_data' in event.__dict__.keys(): self.market_data = self.get_market( order) if event.market_data is None else event.market_data if isinstance(self.market_data,dict): pass elif isinstance(self.market_data,pd.DataFrame): self.market_data=QA_util_to_json_from_pandas(self.market_data)[0] else: self.market_data=self.market_data.to_json()[0] else: self.market_data = self.get_market(order) if self.market_data is not None: order = self.warp(order) return self.dealer.deal(order, self.market_data) else: raise ValueError('MARKET DATA IS NONE CANNOT TRADE') def warp(self, order): """对order/market的封装 [description] Arguments: order {[type]} -- [description] Returns: [type] -- [description] """ # 因为成交模式对时间的封装 if order.order_model == ORDER_MODEL.MARKET: """ 市价单模式 """ if order.frequence is FREQUENCE.DAY: # exact_time = str(datetime.datetime.strptime( # str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = order.datetime[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: order.date = str(order.datetime)[0:10] #_original_marketvalue = order.price*order.amount order.price = (float(self.market_data.get('high')) + float(self.market_data.get('low'))) * 0.5 elif order.order_model == ORDER_MODEL.NEXT_OPEN: # try: # order.date = QA_util_get_next_day(str(order.datetime)[0:10]) # order.datetime = '{} 09:30:00'.format(order.date) # except: # order.datetime = '{} 15:00:00'.format(order.date) # self.market_data = self.get_market(order) # if self.market_data is None: # return order # order.price = float(self.market_data["close"]) raise NotImplementedError elif order.order_model == ORDER_MODEL.CLOSE: """ 收盘价模式 """ try: order.date = order.datetime[0:10] order.datetime = '{} 15:00:00'.format(order.date) except: if len(str(order.datetime)) == 19: pass else: order.datetime = '{} 15:00:00'.format(order.date) order.price = float(self.market_data.get('close')) elif order.order_model == ORDER_MODEL.LIMIT: """ 限价单模式 """ if order.frequence is FREQUENCE.DAY: # exact_time = str(datetime.datetime.strptime( # str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = order.datetime[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: order.date = str(order.datetime)[0:10] elif order.order_model == ORDER_MODEL.STRICT: """ 严格模式 """ if order.frequence is FREQUENCE.DAY: # exact_time = str(datetime.datetime.strptime( # str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = order.datetime[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: order.date = str(order.datetime)[0:10] if order.towards == 1: order.price = float(self.market_data.get('high')) else: order.price = float(self.market_data.get('low')) if order.market_type == MARKET_TYPE.STOCK_CN: if order.towards == ORDER_DIRECTION.BUY: if order.order_model == AMOUNT_MODEL.BY_MONEY: amount = order.money/(order.price*(1+order.commission_coeff)) money = order.money else: amount = order.amount money = order.amount * order.price*(1+order.commission_coeff) order.amount = int(amount / 100) * 100 order.money = money elif order.towards == ORDER_DIRECTION.SELL: if order.order_model == AMOUNT_MODEL.BY_MONEY: amount = order.money/(order.price*(1+order.commission_coeff+order.tax_coeff)) money = order.money else: amount = order.amount money = order.amount * order.price*(1+order.commission_coeff+order.tax_coeff) order.amount = amount order.money = money return order def get_market(self, order): """get_market func [description] Arguments: order {orders} -- [description] Returns: [type] -- [description] """ # 首先判断是否在_quotation里面 if (pd.Timestamp(order.datetime), order.code) in self._quotation.keys(): return self._quotation[(pd.Timestamp(order.datetime), order.code)] else: try: data = self.fetcher[(order.market_type, order.frequence)]( code=order.code, start=order.datetime, end=order.datetime, format='json')[0] if 'vol' in data.keys() and 'volume' not in data.keys(): data['volume'] = data['vol'] elif 'vol' not in data.keys() and 'volume' in data.keys(): data['vol'] = data['volume'] return data except Exception as e: QA_util_log_info('MARKET_ENGING ERROR: {}'.format(e)) return None
class QA_BacktestBroker(QA_Broker): """ QUANTAXIS Broker 部分 回测 股票/指数/期货/债券/ETF/基金 @yutiansut 对于不同的市场规则: 股票市场 t+1 期货/期权/加密货币市场 t+0 股票/加密货币市场不允许卖空 期货/期权市场允许卖空 t+1的市场是 当日的买入 更新持仓- 不更新可卖数量- 资金冻结 当日的卖出 及时更新可用资金 t+0市场是: 当日买入 即时更新持仓和可卖 当日卖出 即时更新 卖空的规则是 允许无仓位的时候卖出证券(按市值和保证金比例限制算) """ def __init__(self, commission_fee_coeff=0.0015, if_nondatabase=False): """[summary] Keyword Arguments: commission_fee_coeff {[type]} -- [description] (default: {0}) environment {[type]} -- [description] (default: {RUNNING_ENVIRONMENT}) if_nondatabase {[type]} -- [description] (default: {False}) """ super().__init__() self.dealer = QA_Dealer(commission_fee_coeff) self.order_handler = QA_OrderHandler() self.engine = { MARKET_TYPE.STOCK_CN: self.dealer.backtest_stock_dealer} self.fetcher = {(MARKET_TYPE.STOCK_CN, FREQUENCE.DAY): QA_fetch_stock_day, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.ONE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.FIVE_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.THIRTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.STOCK_CN, FREQUENCE.SIXTY_MIN): QA_fetch_stock_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.INDEX_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.DAY): QA_fetch_index_day, (MARKET_TYPE.FUND_CN, FREQUENCE.FIFTEEN_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.ONE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.FIVE_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.THIRTY_MIN): QA_fetch_index_min, (MARKET_TYPE.FUND_CN, FREQUENCE.SIXTY_MIN): QA_fetch_index_min} self.commission_fee_coeff = commission_fee_coeff self.market_data = None self.if_nondatabase = if_nondatabase self.name = BROKER_TYPE.BACKETEST self._quotation = {} # 一个可以缓存数据的dict self.broker_data = None def run(self, event): if event.event_type is MARKET_EVENT.QUERY_DATA: # 查询数据部分 code = event.code frequence = event.frequence start = event.start end = start if event.end is None else event.end market_type = event.market_type res = self.query_data(code, start, end, frequence, market_type) if event.callback: event.callback(res) else: return res elif event.event_type is MARKET_EVENT.QUERY_ORDER: self.order_handler.run(event) elif event.event_type is ENGINE_EVENT.UPCOMING_DATA: new_marketdata_dict = event.market_data.dicts for item in new_marketdata_dict.keys(): if item not in self._quotation.keys(): self._quotation[item] = new_marketdata_dict[item] # if self.broker_data is None: # self.broker_data = event.market_data # else: # self.broker_data.append(event.market_data) # self.broker_data=event.market_data elif event.event_type is BROKER_EVENT.RECEIVE_ORDER: self.order_handler.run(event) self.run(QA_Event(event_type=BROKER_EVENT.TRADE, broker=self)) elif event.event_type is BROKER_EVENT.TRADE: event = self.order_handler.run(event) event.message = 'trade' if event.callback: event.callback(event) elif event.event_type is BROKER_EVENT.SETTLE: self.order_handler.run(event) if event.callback: event.callback('settle') def query_data(self, code, start, end, frequence, market_type=None): """ 标准格式是numpy """ try: return self.broker_data.select_time( start, end).select_code(code).to_numpy() except: return self.fetcher[(market_type, frequence)]( code, start, end, frequence=frequence) def receive_order(self, event): """ get the order and choice which market to trade """ order = event.order if 'market_data' in event.__dict__.keys(): self.market_data = self.get_market( order) if event.market_data is None else event.market_data else: self.market_data = self.get_market(order) order = self.warp(order) return self.dealer.deal(order, self.market_data) def warp(self, order): """对order/market的封装 [description] Arguments: order {[type]} -- [description] Returns: [type] -- [description] """ # 因为成交模式对时间的封装 if order.order_model == ORDER_MODEL.MARKET: if order.frequence is FREQUENCE.DAY: # exact_time = str(datetime.datetime.strptime( # str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = order.datetime[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: print(order.datetime) exact_time = str(datetime.datetime.strptime( str(order.datetime), '%Y-%m-%d %H:%M:%S') + datetime.timedelta(minutes=1)) order.date = exact_time[0:10] order.datetime = exact_time self.market_data = self.get_market(order) if self.market_data is None: return order order.price = (float(self.market_data["high"]) + float(self.market_data["low"])) * 0.5 elif order.order_model == ORDER_MODEL.NEXT_OPEN: try: exact_time = str(datetime.datetime.strptime( str(order.datetime), '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = exact_time[0:10] order.datetime = '{} 09:30:00'.format(order.date) except: order.datetime = '{} 15:00:00'.format(order.date) self.market_data = self.get_market(order) if self.market_data is None: return order order.price = float(self.market_data["close"]) elif order.order_model == ORDER_MODEL.CLOSE: try: order.datetime = self.market_data.datetime except: if len(str(order.datetime)) == 19: pass else: order.datetime = '{} 15:00:00'.format(order.date) self.market_data = self.get_market(order) if self.market_data is None: return order order.price = float(self.market_data["close"]) elif order.order_model == ORDER_MODEL.STRICT: '加入严格模式' if order.frequence is FREQUENCE.DAY: exact_time = str(datetime.datetime.strptime( order.datetime, '%Y-%m-%d %H-%M-%S') + datetime.timedelta(day=1)) order.date = exact_time[0:10] order.datetime = '{} 09:30:00'.format(order.date) elif order.frequence in [FREQUENCE.ONE_MIN, FREQUENCE.FIVE_MIN, FREQUENCE.FIFTEEN_MIN, FREQUENCE.THIRTY_MIN, FREQUENCE.SIXTY_MIN]: exact_time = str(datetime.datetime.strptime( order.datetime, '%Y-%m-%d %H-%M-%S') + datetime.timedelta(minute=1)) order.date = exact_time[0:10] order.datetime = exact_time self.market_data = self.get_market(order) if self.market_data is None: return order if order.towards == 1: order.price = float(self.market_data["high"]) else: order.price = float(self.market_data["low"]) return order def get_market(self, order): """get_market func [description] Arguments: order {orders} -- [description] Returns: [type] -- [description] """ # 首先判断是否在_quotation里面 if (order.datetime, order.code) in self._quotation.keys(): return self._quotation[(QA_util_to_datetime(order.datetime), order.code)] else: try: data = self.fetcher[(order.market_type, order.frequence)]( code=order.code, start=order.datetime, end=order.datetime, format='json')[0] if 'vol' in data.keys() and 'volume' not in data.keys(): data['volume'] = data['vol'] elif 'vol' not in data.keys() and 'volume' in data.keys(): data['vol'] = data['volume'] return data except Exception as e: QA_util_log_info('MARKET_ENGING ERROR: {}'.format(e)) return None
class QA_SPEBroker(QA_Broker): def __init__(self): self.order_handler = QA_OrderHandler() self.setting = get_config_SPE() self._session = requests self._endpoint = self.setting.uri self.key = self.setting.key #self.account_headers = ['forzen_cash','balance_available','cash_available','pnl_money_today','total_assets','pnl_holding','market_value','money_available'] self.fillorder_headers = ['name', 'datetime', 'towards', 'price', 'amount', 'money', 'trade_id', 'order_id', 'code', 'shareholder', 'other'] self.holding_headers = ['code', 'name', 'hoding_price', 'price', 'pnl', 'amount', 'sell_available', 'pnl_money', 'holdings', 'total_amount', 'lastest_amounts', 'shareholder'] self.askorder_headers = ['code', 'towards', 'price', 'amount', 'transaction_price', 'transaction_amount', 'status', 'order_time', 'order_id', 'id', 'code', 'shareholders'] def __repr__(self): return ' <QA_BROKER SHIPANE> ' def run(self, event): if event.event_type is BROKER_EVENT.RECEIVE_ORDER: self.order_handler.run(event) self.run(QA_Event(event_type=BROKER_EVENT.TRADE, broker=self)) elif event.event_type is BROKER_EVENT.TRADE: """实盘交易部分!!!!! ATTENTION 这里需要开一个子线程去查询是否成交 ATTENTION """ event = self.order_handler.run(event) event.message = 'trade' if event.callback: event.callback(event) def call(self, func, params=''): try: if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client')) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client')) print(uri) response = self._session.get(uri, params) text = response.text return json.loads(text) except Exception as e: print(e) return None def call_post(self, func, params={}): if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client')) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client')) response = self._session.post(uri, json=params) text = response.text return json.loads(text) def call_delete(self, func, params=''): if self.key == '': uri = '{}/api/v1.0/{}?client={}'.format( self._endpoint, func, params.pop('client')) else: uri = '{}/api/v1.0/{}?key={}&client={}'.format( self._endpoint, func, self.key, params.pop('client')) response = self._session.delete(uri) text = response.text try: if text == '': print('success') return True elif text == '获取提示对话框超时,因为:组件为空': print('do not query too fast') return False else: return json.loads(text) except: return text def data_to_df(self, result): return pd.DataFrame(data=result) #------ functions def ping(self): return self.call("ping", {}) def query_accounts(self, accounts): return self.call("accounts", { 'client': accounts }) def query_positions(self, accounts): """查询现金和持仓 Arguments: accounts {[type]} -- [description] Returns: dict-- {'cash':xxx,'position':xxx} """ data = self.call("positions", { 'client': accounts }) cash_part = data.get('subAccounts', {}).get('人民币', False) if cash_part: cash_available = cash_part.get('可用金额') position_part = data.get('dataTable', False) if position_part: res = data.get('dataTable', False) if res: hold_headers = res['columns'] hold_headers = [cn_en_compare[item] for item in hold_headers] hold_available = pd.DataFrame( res['rows'], columns=hold_headers) return {'cash_available': cash_available, 'hold_available': hold_available.loc[:, ['code', 'amount']].set_index('code').amount} def query_clients(self): return self.call("clients") def query_orders(self, accounts, status='filled'): """查询订单 Arguments: accounts {[type]} -- [description] Keyword Arguments: status {str} -- 'open' 待成交 'filled' 成交 (default: {'filled'}) Returns: [type] -- [description] """ return self.call("orders", { 'client': accounts, 'status': status }) def send_order(self, accounts, code='000001', price=9, amount=100, order_direction=ORDER_DIRECTION.BUY, order_model=ORDER_MODEL.LIMIT): """[summary] Arguments: accounts {[type]} -- [description] code {[type]} -- [description] price {[type]} -- [description] amount {[type]} -- [description] Keyword Arguments: order_direction {[type]} -- [description] (default: {ORDER_DIRECTION.BUY}) order_model {[type]} -- [description] (default: {ORDER_MODEL.LIMIT}) priceType 可选择: 上海交易所: 0 - 限价委托 4 - 五档即时成交剩余撤销 6 - 五档即时成交剩余转限 深圳交易所: 0 - 限价委托 1 - 对手方最优价格委托 2 - 本方最优价格委托 3 - 即时成交剩余撤销委托 4 - 五档即时成交剩余撤销 5 - 全额成交或撤销委托 Returns: [type] -- [description] """ try: return self.call_post('orders', { 'client': accounts, "action": 'BUY' if order_direction == 1 else 'SELL', "symbol": code, "type": order_model, "priceType": 0 if order_model == ORDER_MODEL.LIMIT else 4, "price": price, "amount": amount }) except json.decoder.JSONDecodeError: print(RuntimeError('TRADE ERROR')) return None def cancel_order(self, accounts, orderid): return self.call_delete('orders/{}'.format(orderid), { 'client': accounts }) def cancel_all(self, accounts): return self.call_delete('orders', { 'client': accounts }) def receive_order(self, event): order = event.order callback = self.send_order(accounts=order.account_cookie, code=order.code, amount=order.amount, order_direction=order.towards, order_model=order.order_model) order.realorder_id = callback['id'] order.status = ORDER_STATUS.QUEUED print('success receive order {}'.format(order.realorder_id))
class QA_Market(QA_Trade): """ QUANTAXIS MARKET 部分 交易前置/可连接到多个broker中 暂时还是采用多线程engine模式 session 保存的是 QAAccout 对象 """ def __init__(self, if_start_orderthreading=True, *args, **kwargs): """MARKET的初始化过程 Market的初始属性: session: MARKET的账户字典 _broker: 当前所有的broker集合 TODO: 转移到QAParameter broker: MARKET的broker字典 running_time: MARKET当前的运行时间 last_query_data: MARKET上次获取的数据 if_start_orderthreading: MARKET是否开启订单队列线程的开关 order_handler: 订单队列 Keyword Arguments: if_start_orderthreading {bool} -- 是否在初始化的时候开启查询子线程(实盘需要) (default: {False}) @2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 """ super().__init__() # 以下是待初始化的账户session self.session = {} # 以下都是官方支持的交易前置 self._broker = { BROKER_TYPE.BACKETEST: QA_BacktestBroker, BROKER_TYPE.RANDOM: QA_RandomBroker, BROKER_TYPE.REAL: QA_RealBroker, BROKER_TYPE.SIMULATION: QA_SimulatedBroker, BROKER_TYPE.SHIPANE: QA_SPEBroker, BROKER_TYPE.TTS: QA_TTSBroker, } self.broker = {} self.running_time = None self.last_query_data = None self.if_start_orderthreading = if_start_orderthreading self.order_handler = QA_OrderHandler() def __repr__(self): ''' 输出market市场对象的字符串 ''' return '<QA_Market with {} QA_Broker >'.format(list(self.broker.keys())) def upcoming_data(self, broker, data): ''' 根据更新的市场数据来更新账户信息 broker 为名字, data 是市场数据 被 QABacktest 中run 方法调用 upcoming_data ''' # main thread' # if self.running_time is not None and self.running_time!= data.datetime[0]: # for item in self.broker.keys(): # self._settle(item) self.running_time = data.datetime[0] for account in self.session.values(): account.run(QA_Event( event_type=ENGINE_EVENT.UPCOMING_DATA, # args 附加的参数 market_data=data, broker_name=broker, send_order=self.insert_order, # 🛠todo insert_order = insert_order query_data=self.query_data_no_wait, query_order=self.query_order, query_assets=self.query_assets, query_trade=self.query_trade )) def start(self): ''' 1,开启交易引擎 2,开启订单流线程 :return: ''' self.trade_engine.start() if self.if_start_orderthreading: """查询子线程开关 """ self.start_order_threading() print(threading.enumerate()) def connect(self, broker): if broker in self._broker.keys(): self.broker[broker] = self._broker[broker]() # 在这里实例化 # 2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 # self.trade_engine.create_kernel('{}'.format(broker), daemon=True) # self.trade_engine.start_kernel('{}'.format(broker)) # 2019-02-08 change: 在此 我们删除了BROKER所占用的线程 # 子线程变成功能性线程 # 开启trade事件子线程 return True else: return False def next_tradeday(self): self.order_handler.run( QA_Event( event_type=BROKER_EVENT.NEXT_TRADEDAY, event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def register(self, broker_name, broker): ''' 注册broker :param broker_name: :param broker: :return: ''' if broker_name not in self._broker.keys(): self.broker[broker_name] = broker # self.trade_engine.create_kernel( # '{}'.format(broker_name), # daemon=True # ) # self.trade_engine.start_kernel('{}'.format(broker_name)) return True else: return False def start_order_threading(self): """开启查询子线程(实盘中用) """ self.if_start_orderthreading = True self.order_handler.if_start_orderquery = True self.trade_engine.create_kernel('ORDER', daemon=True) self.trade_engine.start_kernel('ORDER') self.sync_order_and_deal() # self._update_orders() def get_account(self, account_cookie): try: return self.session[account_cookie] except KeyError: print( 'QAMARKET: this account {} is logoff, please login and retry' .format(account_cookie) ) def login(self, broker_name, account_cookie, account=None): """login 登录到交易前置 1,在account和broker间同步信息 2,order_handler订阅account和对应的broker 2018-07-02 在实盘中,登录到交易前置后,需要同步资产状态 Arguments: broker_name {[type]} -- [description] account_cookie {[type]} -- [description] Keyword Arguments: account {[type]} -- [description] (default: {None}) Returns: [type] -- [description] """ res = False if account is None: if account_cookie not in self.session.keys(): # self.session[account_cookie] = QA_Account( # account_cookie=account_cookie, # broker=broker_name # ) if self.sync_account(broker_name, account_cookie): res = True if self.if_start_orderthreading and res: # self.order_handler.subscribe( self.session[account_cookie], self.broker[broker_name] ) else: if account_cookie not in self.session.keys(): account.broker = broker_name self.session[account_cookie] = account if self.sync_account(broker_name, account_cookie): res = True if self.if_start_orderthreading and res: # self.order_handler.subscribe( account, self.broker[broker_name] ) if res: return res else: try: self.session.pop(account_cookie) except: pass return False def sync_order_and_deal(self): self.order_handler.if_start_orderquery = True self._sync_orders() def stop_sync_order_and_deal(self): self.order_handler.if_start_orderquery = False def sync_account(self, broker_name, account_cookie): """同步账户信息 若broker是回测的,那么不用同步,账户直接就是初始化的 若broker是其他的,那么需要和broker同步信息,从broker获取初始持仓信息 这是因为,回测刚开始的账户都是需要初始化的,不需要从broker核对 Arguments: broker_id {[type]} -- [description] account_cookie {[type]} -- [description] """ try: if isinstance(self.broker[broker_name], QA_BacktestBroker): pass else: self.session[account_cookie].sync_account( self.broker[broker_name].query_positions(account_cookie) ) return True except Exception as e: print(e) return False def logout(self, account_cookie, broker_name): if account_cookie not in self.session.keys(): return False else: self.order_handler.unsubscribe( self.session[account_cookie], self.broker[broker_name] ) self.session.pop(account_cookie) def get_trading_day(self): return self.running_time def get_account_cookie(self): return list(self.session.keys()) def insert_order( self, account_cookie, amount, amount_model, time, code, price, order_model, towards, market_type, frequence, broker_name, money=None ): #strDbg = QA_util_random_with_topic("QA_Market.insert_order") print( ">-----------------------insert_order----------------------------->", "QA_Market.insert_order" ) flag = False # 行情切片 bar/tick/realtime price_slice = self.query_data_no_wait( broker_name=broker_name, frequence=frequence, market_type=market_type, code=code, start=time ) price_slice = price_slice if price_slice is None else price_slice[0] if order_model in [ORDER_MODEL.CLOSE, ORDER_MODEL.NEXT_OPEN]: if isinstance(price_slice, np.ndarray): if (price_slice != np.array(None)).any(): price = float(price_slice[4]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif isinstance(price_slice, dict): if price_slice is not None: price = float(price_slice['close']) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif isinstance(price_slice, list): if price_slice is not None: price = float(price_slice[4]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif order_model is ORDER_MODEL.MARKET: if isinstance(price_slice, np.ndarray): if (price_slice != np.array(None)).any(): price = float(price_slice[1]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif isinstance(price_slice, dict): if price_slice is not None: price = float(price_slice['open']) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif order_model is ORDER_MODEL.LIMIT: flag = True print( amount, amount_model, time, code, price, order_model, towards, money ) if flag: order = self.get_account(account_cookie).send_order( amount=amount, amount_model=amount_model, time=time, code=code, price=price, order_model=order_model, towards=towards, money=money ) if order: self.order_handler.run( QA_Event( broker=self.broker[self.get_account(account_cookie ).broker], event_type=BROKER_EVENT.RECEIVE_ORDER, order=order, market_data=price_slice, callback=self.on_insert_order ) ) else: pass def on_insert_order(self, order: QA_Order): print(order) print(order.status) if order.status == ORDER_STATUS.FAILED: """如果订单创建失败, 恢复状态 如果是买入单 恢复金钱 money 如果是卖出单 恢复股数 sell_available """ self.session[order.account_cookie].cancel_order(order) else: if order.order_model in [ORDER_MODEL.MARKET, ORDER_MODEL.CLOSE, ORDER_MODEL.LIMIT]: self.order_handler._trade( order, self.session[order.account_cookie] ) # 直接交易 elif order.order_model in [ORDER_MODEL.NEXT_OPEN]: pass def _renew_account(self): for account in self.session.values(): account.run(QA_Event(event_type=ACCOUNT_EVENT.SETTLE)) def _sync_position(self): self.order_handler.run( QA_Event( event_type=MARKET_EVENT.QUERY_POSITION, account_cookie=list(self.session.keys()), broker=[ self.broker[item.broker] for item in self.session.values() ] ) ) def _sync_deals(self): self.order_handler.run( QA_Event( event_type=MARKET_EVENT.QUERY_DEAL, account_cookie=list(self.session.keys()), broker=[ self.broker[item.broker] for item in self.session.values() ], event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def _sync_orders(self): # account_cookie=list(self.session.keys()), # broker=[self.broker[item.broker] # for item in self.session.values()], # 注意: 一定要给子线程的队列@@@!!! # 2018-08-08 yutiansut # 这个callback实现了子线程方法的自我驱动和异步任务 self.order_handler.run( QA_Event( event_type=MARKET_EVENT.QUERY_ORDER, event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def sync_strategy(self, broker_name, account_cookie): """同步 账户/委托/成交 Arguments: broker_name {[type]} -- [description] account_cookie {[type]} -- [description] """ pass def cancel_order(self, broker_name, account_cookie, order_id): pass def cancel_all(self, broker_name, account_cookie): try: self.broker[broker_name].cancel_all(account_cookie) except Exception as e: print(e) def query_orders(self, account_cookie): ''' 从订单队列.订单状态中获取指定账户的所有订单信息 :param account_cookie: :return: ''' return self.order_handler.order_status.xs(account_cookie) def query_order(self, account_cookie, realorder_id): ''' 从订单队列.订单状态中获取指定账户的指定订单的信息 :param account_cookie: :param realorder_id: :return: ''' return self.order_handler.order_status.loc[account_cookie, realorder_id] def query_assets(self, account_cookie): ''' 查看指定账户的初始资产 :param account_cookie: :return: ''' return self.get_account(account_cookie).init_assets def query_position(self, account_cookie): ''' 查看指定账户的持仓 :param account_cookie: :return: ''' return self.get_account(account_cookie).hold def query_cash(self, account_cookie): ''' 查看指定账户的现金 :param account_cookie: :return: ''' return self.get_account(account_cookie).cash_available def query_data_no_wait( self, broker_name, frequence, market_type, code, start, end=None ): ''' 从broker获取数据 :param broker_name: :param frequence: :param market_type: :param code: :param start: :param end: :return: ''' return self.broker[broker_name].run( event=QA_Event( event_type=MARKET_EVENT.QUERY_DATA, frequence=frequence, market_type=market_type, code=code, start=start, end=end ) ) query_data = query_data_no_wait def query_currentbar(self, broker_name, market_type, code): return self.broker[broker_name].run( event=QA_Event( event_type=MARKET_EVENT.QUERY_DATA, frequence=FREQUENCE.CURRENT, market_type=market_type, code=code, start=self.running_time, end=None ) ) def on_query_data(self, data): print('ON QUERY') print(data) self.last_query_data = data def on_trade_event(self, event): print('ON TRADE') print(event.res) def _trade(self, event): "内部函数" print('==================================market enging: trade') print(self.order_handler.order_queue.pending) print('==================================') self.order_handler._trade() print('done') def _settle(self, broker_name, callback=False): #strDbg = QA_util_random_with_topic("QA_Market._settle") print( ">-----------------------_settle----------------------------->", "QA_Market._settle" ) # 向事件线程发送BROKER的SETTLE事件 # 向事件线程发送ACCOUNT的SETTLE事件 for account in self.session.values(): """t0账户先结算当日仓位 """ if account.broker == broker_name: if account.running_environment == RUNNING_ENVIRONMENT.TZERO: for order in account.close_positions_order: price_slice = self.query_data_no_wait( broker_name=order.broker, frequence=order.frequence, market_type=order.market_type, code=order.code, start=order.datetime ) price_slice = price_slice if price_slice is None else price_slice[ 0] self.order_handler.run( QA_Event( broker=self.broker[account.broker], event_type=BROKER_EVENT.RECEIVE_ORDER, order=order, market_data=price_slice, callback=self.on_insert_order ) ) self._trade(event=QA_Event(broker_name=broker_name)) self.broker[broker_name].run( QA_Event( event_type=BROKER_EVENT.SETTLE, broker=self.broker[broker_name], callback=callback ) ) for account in self.session.values(): print(account.history) account.settle() print('===== SETTLED {} ====='.format(self.running_time)) def settle_order(self): """交易前置结算 1. 回测: 交易队列清空,待交易队列标记SETTLE 2. 账户每日结算 3. broker结算更新 """ if self.if_start_orderthreading: self.order_handler.run( QA_Event( event_type=BROKER_EVENT.SETTLE, event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def every_day_start(self): """盘前准备 1. 计算盘前信号 2. 账户同步 """ pass def _close(self): pass def clear(self): return self.trade_engine.clear()
class QA_Market(QA_Trade): """ QUANTAXIS MARKET 部分 交易前置/可连接到多个broker中 暂时还是采用多线程engine模式 session 保存的是 QAAccout 对象 """ def __init__(self, if_start_orderthreading=True, *args, **kwargs): """[summary] Keyword Arguments: if_start_orderthreading {bool} -- 是否在初始化的时候开启查询子线程(实盘需要) (default: {False}) @2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 """ super().__init__() # 以下是待初始化的账户session self.session = {} # 以下都是官方支持的交易前置 self._broker = { BROKER_TYPE.BACKETEST: QA_BacktestBroker, BROKER_TYPE.RANODM: QA_RandomBroker, BROKER_TYPE.REAL: QA_RealBroker, BROKER_TYPE.SIMULATION: QA_SimulatedBroker, BROKER_TYPE.SHIPANE: QA_SPEBroker } self.broker = {} self.running_time = None self.last_query_data = None self.if_start_orderthreading = if_start_orderthreading self.order_handler = QA_OrderHandler() def __repr__(self): ''' 输出market市场对象的字符串 ''' return '<QA_Market with {} QA_Broker >'.format(list( self.broker.keys())) def upcoming_data(self, broker, data): ''' 更新市场数据 broker 为名字, data 是市场数据 被 QABacktest 中run 方法调用 upcoming_data ''' # main thread' # if self.running_time is not None and self.running_time!= data.datetime[0]: # for item in self.broker.keys(): # self._settle(item) self.running_time = data.datetime[0] for item in self.session.values(): # session里面是已经注册的account self.submit( QA_Task( worker=item, # item 是Account 类型, 是 QA_Work类型, 处理这个 事件 event=QA_Event( event_type=ENGINE_EVENT.UPCOMING_DATA, # args 附加的参数 market_data=data, broker_name=broker, send_order=self. insert_order, # 🛠todo insert_order = insert_order query_data=self.query_data_no_wait, query_order=self.query_order, query_assets=self.query_assets, query_trade=self.query_trade)), nowait=True) def submit(self, QATask, nowait=False): """submit 一个任务给QAMarket的event_queue Arguments: QATask {[type]} -- [description] QATask 需要有 - worker (需要这个类继承了QA_Worker) - engine(默认qamarket所在的thread) - event - QA_Event - event_type - 自定义参数 - callback Keyword Arguments: nowait {bool} -- [description] (default: {False}) """ assert isinstance(QATask, QA_Task) if nowait: self.event_queue.put_nowait(QATask) else: self.submit(QATask) def start(self): self.trade_engine.start() if self.if_start_orderthreading: """查询子线程开关 """ self.start_order_threading() # self.trade_engine.create_kernel('MARKET') # self.trade_engine.start_kernel('MARKET') def connect(self, broker): if broker in self._broker.keys(): self.broker[broker] = self._broker[broker]() # 在这里实例化 # 2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 self.trade_engine.create_kernel('{}'.format(broker), daemon=True) self.trade_engine.start_kernel('{}'.format(broker)) # 开启trade事件子线程 return True else: return False def register(self, broker_name, broker): if broker_name not in self._broker.keys(): self.broker[broker_name] = broker self.trade_engine.create_kernel('{}'.format(broker_name), daemon=True) self.trade_engine.start_kernel('{}'.format(broker_name)) return True else: return False def start_order_threading(self): """开启查询子线程(实盘中用) """ self.if_start_orderthreading = True self.order_handler.if_start_orderquery = True self.trade_engine.create_kernel('ORDER', daemon=True) self.trade_engine.start_kernel('ORDER') # self._update_orders() def get_account(self, account_cookie): try: return self.session[account_cookie] except KeyError: print( 'QAMARKET: this account {} is logoff, please login and retry'. format(account_cookie)) def login(self, broker_name, account_cookie, account=None): """login 登录到交易前置 2018-07-02 在实盘中,登录到交易前置后,需要同步资产状态 Arguments: broker_name {[type]} -- [description] account_cookie {[type]} -- [description] Keyword Arguments: account {[type]} -- [description] (default: {None}) Returns: [type] -- [description] """ res = False if account is None: if account_cookie not in self.session.keys(): self.session[account_cookie] = QA_Account( account_cookie=account_cookie, broker=broker_name) if self.sync_account(broker_name, account_cookie): res = True if self.if_start_orderthreading and res: # self.order_handler.subscribe(self.session[account_cookie], self.broker[broker_name]) else: if account_cookie not in self.session.keys(): account.broker = broker_name self.session[account_cookie] = account if self.sync_account(broker_name, account_cookie): res = True if self.if_start_orderthreading and res: # self.order_handler.subscribe(account, self.broker[broker_name]) if res: return res else: try: self.session.pop(account_cookie) except: pass return False def sync_order_and_deal(self): self.if_start_orderquery = True # self._sync_orders() def stop_sync_order_and_deal(self): self.if_start_orderquery = False def sync_account(self, broker_name, account_cookie): """同步账户信息 Arguments: broker_id {[type]} -- [description] account_cookie {[type]} -- [description] """ try: if isinstance(self.broker[broker_name], QA_BacktestBroker): pass else: self.session[account_cookie].sync_account( self.broker[broker_name].query_positions(account_cookie)) return True except Exception as e: print(e) return False def logout(self, account_cookie, broker_name): if account_cookie not in self.session.keys(): return False else: self.order_handler.unsubscribe(self.session[account_cookie], self.broker[broker_name]) self.session.pop(account_cookie) def get_trading_day(self): return self.running_time def get_account_id(self): return list(self.session.keys()) def insert_order(self, account_cookie, amount, amount_model, time, code, price, order_model, towards, market_type, frequence, broker_name, money=None): #strDbg = QA_util_random_with_topic("QA_Market.insert_order") #print(">-----------------------insert_order----------------------------->", strDbg) flag = False #行情切片 bar/tick/realtime price_slice = self.query_data_no_wait(broker_name=broker_name, frequence=frequence, market_type=market_type, code=code, start=time) price_slice = price_slice if price_slice is None else price_slice[0] if order_model in [ORDER_MODEL.CLOSE, ORDER_MODEL.NEXT_OPEN]: if isinstance(price_slice, np.ndarray): if (price_slice != np.array(None)).any(): price = float(price_slice[4]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ') QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model)) elif isinstance(price_slice, dict): if price_slice is not None: price = float(price_slice['close']) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ') QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model)) elif isinstance(price_slice, list): if price_slice is not None: price = float(price_slice[4]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ') QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model)) elif order_model is ORDER_MODEL.MARKET: if isinstance(price_slice, np.ndarray): if (price_slice != np.array(None)).any(): price = float(price_slice[1]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ') QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model)) elif isinstance(price_slice, dict): if price_slice is not None: price = float(price_slice['open']) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ') QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model)) elif order_model is ORDER_MODEL.LIMIT: flag = True if flag: order = self.get_account(account_cookie).send_order( amount=amount, amount_model=amount_model, time=time, code=code, price=price, order_model=order_model, towards=towards, money=money) if order: # print(order) self.submit(QA_Task(worker=self.order_handler, engine='ORDER', event=QA_Event( broker=self.broker[self.get_account( account_cookie).broker], event_type=BROKER_EVENT.RECEIVE_ORDER, order=order, market_data=price_slice, callback=self.on_insert_order)), nowait=True) else: pass #print("<-----------------------insert_order-----------------------------<", strDbg) def on_insert_order(self, order): print('on_insert_order') print(order) print(order.status) if order.status == ORDER_STATUS.FAILED: """如果订单创建失败, 恢复状态 如果是买入单 恢复金钱 money 如果是卖出单 恢复股数 sell_available """ self.session[order.account_cookie].cancel_order(order) def _renew_account(self): for account in self.session.values(): self.submit( QA_Task(worker=account, event=QA_Event(event_type=ACCOUNT_EVENT.SETTLE))) def _sync_position(self): self.submit(QA_Task(worker=self.order_handler, engine='ORDER', event=QA_Event( event_type=MARKET_EVENT.QUERY_POSITION, account_cookie=list(self.session.keys()), broker=[ self.broker[item.broker] for item in self.session.values() ])), nowait=True) def _sync_deals(self): self.submit(QA_Task( worker=self.order_handler, engine='ORDER', event=QA_Event( event_type=MARKET_EVENT.QUERY_DEAL, account_cookie=list(self.session.keys()), broker=[ self.broker[item.broker] for item in self.session.values() ], event_queue=self.trade_engine.kernels_dict['ORDER'].queue)), nowait=True) def _sync_orders(self): self.submit( QA_Task( worker=self.order_handler, engine='ORDER', event=QA_Event( event_type=MARKET_EVENT.QUERY_ORDER, # account_cookie=list(self.session.keys()), # broker=[self.broker[item.broker] # for item in self.session.values()], # 注意: 一定要给子线程的队列@@@!!! # 2018-08-08 yutiansut # 这个callback实现了子线程方法的自我驱动和异步任务 event_queue=self.trade_engine.kernels_dict['ORDER'].queue) ), nowait=True) def sync_strategy(self, broker_name, account_cookie): """同步 账户/委托/成交 Arguments: broker_name {[type]} -- [description] account_cookie {[type]} -- [description] """ pass def cancel_order(self, broker_name, account_cookie, order_id): pass def cancel_all(self, broker_name, account_cookie): try: self.broker[broker_name].cancel_all(account_cookie) except Exception as e: print(e) def query_order(self, account_cookie, realorder_id): # res = self.submit( # QA_Task( # worker=self.broker[self.get_account( # account_cookie).broker], # engine=self.get_account( # account_cookie).broker, # event=QA_Event( # broker=self.broker[self.get_account( # account_cookie).broker], # order_id=order_id # ) # ),nowait=True) return self.order_handler.order_status.loc[account_cookie, realorder_id] def query_assets(self, account_cookie): return self.get_account(account_cookie).assets def query_position(self, account_cookie): return self.get_account(account_cookie).hold def query_cash(self, account_cookie): return self.get_account(account_cookie).cash_available def query_data_no_wait(self, broker_name, frequence, market_type, code, start, end=None): return self.broker[broker_name].run( event=QA_Event(event_type=MARKET_EVENT.QUERY_DATA, frequence=frequence, market_type=market_type, code=code, start=start, end=end)) def query_data(self, broker_name, frequence, market_type, code, start, end=None): self.submit( QA_Task(worker=self.broker[broker_name], engine=broker_name, event=QA_Event(event_type=MARKET_EVENT.QUERY_DATA, frequence=frequence, market_type=market_type, code=code, start=start, end=end, callback=self.on_query_data))) def query_currentbar(self, broker_name, market_type, code): return self.broker[broker_name].run( event=QA_Event(event_type=MARKET_EVENT.QUERY_DATA, frequence=FREQUENCE.CURRENT, market_type=market_type, code=code, start=self.running_time, end=None)) def on_query_data(self, data): print('ON QUERY') print(data) self.last_query_data = data def on_trade_event(self, event): print('ON TRADE') print(event.res) def _trade(self, event): "内部函数" self.submit( QA_Task(worker=self.broker[event.broker_name], engine=event.broker_name, event=QA_Event(event_type=BROKER_EVENT.TRADE, broker=self.broker[event.broker_name], broker_name=event.broker_name, callback=self.on_trade_event))) def _settle(self, broker_name, callback=False): #strDbg = QA_util_random_with_topic("QA_Market._settle") #print(">-----------------------_settle----------------------------->", strDbg) # 向事件线程发送BROKER的SETTLE事件 # 向事件线程发送ACCOUNT的SETTLE事件 for account in self.session.values(): """t0账户先结算当日仓位 """ if account.running_environment == RUNNING_ENVIRONMENT.TZERO: for order in account.close_positions_order: self.submit( QA_Task(worker=self.broker[account.broker], engine=account.broker, event=QA_Event( event_type=BROKER_EVENT.RECEIVE_ORDER, order=order, callback=self.on_insert_order))) """broker中账户结算 """ if account.broker == broker_name: self.submit(QA_Task( worker=account, engine=broker_name, event=QA_Event(event_type=ACCOUNT_EVENT.SETTLE)), nowait=True) """broker线程结算 """ self.submit(QA_Task(worker=self.broker[broker_name], engine=broker_name, event=QA_Event(event_type=BROKER_EVENT.SETTLE, broker=self.broker[broker_name], callback=callback)), nowait=True) self.settle_order() print('===== SETTLED {} ====='.format(self.running_time)) def settle_order(self): """交易前置结算 1. 回测: 交易队列清空,待交易队列标记SETTLE 2. 账户每日结算 3. broker结算更新 """ if self.if_start_orderthreading: # print('setttle_order') self.submit(QA_Task(worker=self.order_handler, engine='ORDER', event=QA_Event(event_type=BROKER_EVENT.SETTLE, event_queue=self.trade_engine. kernels_dict['ORDER'].queue)), nowait=True) def every_day_start(self): """盘前准备 1. 计算盘前信号 2. 账户同步 """ pass def _close(self): pass def clear(self): return self.trade_engine.clear()
class QA_Market(QA_Trade): """ QUANTAXIS MARKET 部分 交易前置/可连接到多个broker中 暂时还是采用多线程engine模式 session 保存的是 QAAccout 对象 """ def __init__(self, if_start_orderthreading=True, *args, **kwargs): """MARKET的初始化过程 Keyword Arguments: if_start_orderthreading {bool} -- 是否在初始化的时候开启查询子线程(实盘需要) (default: {False}) @2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 """ super().__init__() # 以下是待初始化的账户session self.session = {} # 以下都是官方支持的交易前置 self._broker = { BROKER_TYPE.BACKETEST: QA_BacktestBroker, BROKER_TYPE.RANDOM: QA_RandomBroker, BROKER_TYPE.REAL: QA_RealBroker, BROKER_TYPE.SIMULATION: QA_SimulatedBroker, BROKER_TYPE.SHIPANE: QA_SPEBroker, BROKER_TYPE.TTS: QA_TTSBroker, } self.broker = {} self.running_time = None self.last_query_data = None self.if_start_orderthreading = if_start_orderthreading self.order_handler = QA_OrderHandler() def __repr__(self): ''' 输出market市场对象的字符串 ''' return '<QA_Market with {} QA_Broker >'.format(list(self.broker.keys())) def upcoming_data(self, broker, data): ''' 更新市场数据 broker 为名字, data 是市场数据 被 QABacktest 中run 方法调用 upcoming_data ''' # main thread' # if self.running_time is not None and self.running_time!= data.datetime[0]: # for item in self.broker.keys(): # self._settle(item) self.running_time = data.datetime[0] for account in self.session.values(): account.run(QA_Event( event_type=ENGINE_EVENT.UPCOMING_DATA, # args 附加的参数 market_data=data, broker_name=broker, send_order=self.insert_order, # 🛠todo insert_order = insert_order query_data=self.query_data_no_wait, query_order=self.query_order, query_assets=self.query_assets, query_trade=self.query_trade )) def start(self): self.trade_engine.start() if self.if_start_orderthreading: """查询子线程开关 """ self.start_order_threading() print(threading.enumerate()) def connect(self, broker): if broker in self._broker.keys(): self.broker[broker] = self._broker[broker]() # 在这里实例化 # 2018-08-06 change : 子线程全部变成后台线程 market线程崩了 子线程全部结束 # self.trade_engine.create_kernel('{}'.format(broker), daemon=True) # self.trade_engine.start_kernel('{}'.format(broker)) # 2019-02-08 change: 在此 我们删除了BROKER所占用的线程 # 子线程变成功能性线程 # 开启trade事件子线程 return True else: return False def next_tradeday(self): self.order_handler.run( QA_Event( event_type=BROKER_EVENT.NEXT_TRADEDAY, event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def register(self, broker_name, broker): if broker_name not in self._broker.keys(): self.broker[broker_name] = broker # self.trade_engine.create_kernel( # '{}'.format(broker_name), # daemon=True # ) # self.trade_engine.start_kernel('{}'.format(broker_name)) return True else: return False def start_order_threading(self): """开启查询子线程(实盘中用) """ self.if_start_orderthreading = True self.order_handler.if_start_orderquery = True self.trade_engine.create_kernel('ORDER', daemon=True) self.trade_engine.start_kernel('ORDER') self.sync_order_and_deal() # self._update_orders() def get_account(self, account_cookie): try: return self.session[account_cookie] except KeyError: print( 'QAMARKET: this account {} is logoff, please login and retry' .format(account_cookie) ) def login(self, broker_name, account_cookie, account=None): """login 登录到交易前置 2018-07-02 在实盘中,登录到交易前置后,需要同步资产状态 Arguments: broker_name {[type]} -- [description] account_cookie {[type]} -- [description] Keyword Arguments: account {[type]} -- [description] (default: {None}) Returns: [type] -- [description] """ res = False if account is None: if account_cookie not in self.session.keys(): self.session[account_cookie] = QA_Account( account_cookie=account_cookie, broker=broker_name ) if self.sync_account(broker_name, account_cookie): res = True if self.if_start_orderthreading and res: # self.order_handler.subscribe( self.session[account_cookie], self.broker[broker_name] ) else: if account_cookie not in self.session.keys(): account.broker = broker_name self.session[account_cookie] = account if self.sync_account(broker_name, account_cookie): res = True if self.if_start_orderthreading and res: # self.order_handler.subscribe( account, self.broker[broker_name] ) if res: return res else: try: self.session.pop(account_cookie) except: pass return False def sync_order_and_deal(self): self.order_handler.if_start_orderquery = True self._sync_orders() def stop_sync_order_and_deal(self): self.order_handler.if_start_orderquery = False def sync_account(self, broker_name, account_cookie): """同步账户信息 Arguments: broker_id {[type]} -- [description] account_cookie {[type]} -- [description] """ try: if isinstance(self.broker[broker_name], QA_BacktestBroker): pass else: self.session[account_cookie].sync_account( self.broker[broker_name].query_positions(account_cookie) ) return True except Exception as e: print(e) return False def logout(self, account_cookie, broker_name): if account_cookie not in self.session.keys(): return False else: self.order_handler.unsubscribe( self.session[account_cookie], self.broker[broker_name] ) self.session.pop(account_cookie) def get_trading_day(self): return self.running_time def get_account_cookie(self): return list(self.session.keys()) def insert_order( self, account_cookie, amount, amount_model, time, code, price, order_model, towards, market_type, frequence, broker_name, money=None ): #strDbg = QA_util_random_with_topic("QA_Market.insert_order") print( ">-----------------------insert_order----------------------------->", "QA_Market.insert_order" ) flag = False # 行情切片 bar/tick/realtime price_slice = self.query_data_no_wait( broker_name=broker_name, frequence=frequence, market_type=market_type, code=code, start=time ) price_slice = price_slice if price_slice is None else price_slice[0] if order_model in [ORDER_MODEL.CLOSE, ORDER_MODEL.NEXT_OPEN]: if isinstance(price_slice, np.ndarray): if (price_slice != np.array(None)).any(): price = float(price_slice[4]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif isinstance(price_slice, dict): if price_slice is not None: price = float(price_slice['close']) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif isinstance(price_slice, list): if price_slice is not None: price = float(price_slice[4]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif order_model is ORDER_MODEL.MARKET: if isinstance(price_slice, np.ndarray): if (price_slice != np.array(None)).any(): price = float(price_slice[1]) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif isinstance(price_slice, dict): if price_slice is not None: price = float(price_slice['open']) flag = True else: QA_util_log_info( 'MARKET WARING: SOMEING WRONG WITH ORDER \n ' ) QA_util_log_info( 'code {} date {} price {} order_model {} amount_model {}' .format(code, time, price, order_model, amount_model) ) elif order_model is ORDER_MODEL.LIMIT: flag = True print( amount, amount_model, time, code, price, order_model, towards, money ) if flag: order = self.get_account(account_cookie).send_order( amount=amount, amount_model=amount_model, time=time, code=code, price=price, order_model=order_model, towards=towards, money=money ) if order: self.order_handler.run( QA_Event( broker=self.broker[self.get_account(account_cookie ).broker], event_type=BROKER_EVENT.RECEIVE_ORDER, order=order, market_data=price_slice, callback=self.on_insert_order ) ) else: pass def on_insert_order(self, order: QA_Order): print(order) print(order.status) if order.status == ORDER_STATUS.FAILED: """如果订单创建失败, 恢复状态 如果是买入单 恢复金钱 money 如果是卖出单 恢复股数 sell_available """ self.session[order.account_cookie].cancel_order(order) else: if order.order_model in [ORDER_MODEL.MARKET, ORDER_MODEL.CLOSE, ORDER_MODEL.LIMIT]: self.order_handler._trade( order, self.session[order.account_cookie] ) # 直接交易 elif order.order_model in [ORDER_MODEL.NEXT_OPEN]: pass def _renew_account(self): for account in self.session.values(): account.run(QA_Event(event_type=ACCOUNT_EVENT.SETTLE)) def _sync_position(self): self.order_handler.run( QA_Event( event_type=MARKET_EVENT.QUERY_POSITION, account_cookie=list(self.session.keys()), broker=[ self.broker[item.broker] for item in self.session.values() ] ) ) def _sync_deals(self): self.order_handler.run( QA_Event( event_type=MARKET_EVENT.QUERY_DEAL, account_cookie=list(self.session.keys()), broker=[ self.broker[item.broker] for item in self.session.values() ], event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def _sync_orders(self): # account_cookie=list(self.session.keys()), # broker=[self.broker[item.broker] # for item in self.session.values()], # 注意: 一定要给子线程的队列@@@!!! # 2018-08-08 yutiansut # 这个callback实现了子线程方法的自我驱动和异步任务 self.order_handler.run( QA_Event( event_type=MARKET_EVENT.QUERY_ORDER, event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def sync_strategy(self, broker_name, account_cookie): """同步 账户/委托/成交 Arguments: broker_name {[type]} -- [description] account_cookie {[type]} -- [description] """ pass def cancel_order(self, broker_name, account_cookie, order_id): pass def cancel_all(self, broker_name, account_cookie): try: self.broker[broker_name].cancel_all(account_cookie) except Exception as e: print(e) def query_orders(self, account_cookie): return self.order_handler.order_status.xs(account_cookie) def query_order(self, account_cookie, realorder_id): return self.order_handler.order_status.loc[account_cookie, realorder_id] def query_assets(self, account_cookie): return self.get_account(account_cookie).init_assets def query_position(self, account_cookie): return self.get_account(account_cookie).hold def query_cash(self, account_cookie): return self.get_account(account_cookie).cash_available def query_data_no_wait( self, broker_name, frequence, market_type, code, start, end=None ): return self.broker[broker_name].run( event=QA_Event( event_type=MARKET_EVENT.QUERY_DATA, frequence=frequence, market_type=market_type, code=code, start=start, end=end ) ) query_data = query_data_no_wait def query_currentbar(self, broker_name, market_type, code): return self.broker[broker_name].run( event=QA_Event( event_type=MARKET_EVENT.QUERY_DATA, frequence=FREQUENCE.CURRENT, market_type=market_type, code=code, start=self.running_time, end=None ) ) def on_query_data(self, data): print('ON QUERY') print(data) self.last_query_data = data def on_trade_event(self, event): print('ON TRADE') print(event.res) def _trade(self, event): "内部函数" print('==================================market enging: trade') print(self.order_handler.order_queue.pending) print('==================================') self.order_handler._trade() print('done') def _settle(self, broker_name, callback=False): #strDbg = QA_util_random_with_topic("QA_Market._settle") print( ">-----------------------_settle----------------------------->", "QA_Market._settle" ) # 向事件线程发送BROKER的SETTLE事件 # 向事件线程发送ACCOUNT的SETTLE事件 for account in self.session.values(): """t0账户先结算当日仓位 """ if account.broker == broker_name: if account.running_environment == RUNNING_ENVIRONMENT.TZERO: for order in account.close_positions_order: price_slice = self.query_data_no_wait( broker_name=order.broker, frequence=order.frequence, market_type=order.market_type, code=order.code, start=order.datetime ) price_slice = price_slice if price_slice is None else price_slice[ 0] self.order_handler.run( QA_Event( broker=self.broker[account.broker], event_type=BROKER_EVENT.RECEIVE_ORDER, order=order, market_data=price_slice, callback=self.on_insert_order ) ) self._trade(event=QA_Event(broker_name=broker_name)) self.broker[broker_name].run( QA_Event( event_type=BROKER_EVENT.SETTLE, broker=self.broker[broker_name], callback=callback ) ) for account in self.session.values(): print(account.history) account.settle() print('===== SETTLED {} ====='.format(self.running_time)) def settle_order(self): """交易前置结算 1. 回测: 交易队列清空,待交易队列标记SETTLE 2. 账户每日结算 3. broker结算更新 """ if self.if_start_orderthreading: self.order_handler.run( QA_Event( event_type=BROKER_EVENT.SETTLE, event_queue=self.trade_engine.kernels_dict['ORDER'].queue ) ) def every_day_start(self): """盘前准备 1. 计算盘前信号 2. 账户同步 """ pass def _close(self): pass def clear(self): return self.trade_engine.clear()