def get_account_apis(): openapi_client = TradeClient(client_config, logger=logger) openapi_client.get_managed_accounts() # 获取订单 openapi_client.get_orders() # 获取持仓 openapi_client.get_positions() # 获取资产 openapi_client.get_assets()
def __init__(self): self.client_config = get_client_config() self.trade_client = TradeClient(self.client_config) self.openapi_client = QuoteClient(self.client_config, logger=logger) # 初始化 pushclient protocol, host, port = self.client_config.socket_host_port self.push_client = PushClient(host, port, use_ssl=(protocol == 'ssl')) self.push_client.connect(self.client_config.tiger_id, self.client_config.private_key)
def algo_order_demo(): account = client_config.account openapi_client = TradeClient(client_config, logger=logger) contract = stock_contract(symbol='AAPL', currency='USD') params = algo_order_params(start_time='2020-11-19 23:00:00', end_time='2020-11-19 23:50:00', no_take_liq=True, allow_past_end_time=True, participation_rate=0.1) order = algo_order(account, contract, 'BUY', 1000, 'VWAP', algo_params=params, limit_price=100.0) openapi_client.place_order(order) print(order)
def get_account_apis(): openapi_client = TradeClient(client_config, logger=logger) openapi_client.get_managed_accounts() # 获取订单 openapi_client.get_orders() # 获取未成交订单 # openapi_client.get_open_orders() # 获取已成交订单 # openapi_client.get_filled_orders(start_time='2019-05-01', end_time='2019-05-21') # 获取持仓 openapi_client.get_positions() # 获取资产 openapi_client.get_assets()
def connect_trade(self): """ Connect to trade server. """ self.trade_client = TradeClient(self.client_config) try: self.add_task(self.query_order) self.add_task(self.query_position) self.add_task(self.query_account) except ApiException: self.write_log(" transaction interface connection failure ") return self.write_log(" successful transaction interface ")
def connect_trade(self): """ Connect to trade server. """ self.trade_client = TradeClient(self.client_config) try: self.add_task(self.query_order) self.add_task(self.query_position) self.add_task(self.query_account) except ApiException: self.write_log("交易接口连接失败") return self.write_log("交易接口连接成功")
def __init__(self, account_type, config, sandbox_debug=False, logger_name=None, open_time_adj=0, close_time_adj=0): # get logger self.logger = Tiger.defualt_logger if ( logger_name is None) else logging.getLogger(logger_name) # read user info, position record from local files self.__user_info = io_util.read_config(file_path=config['tiger_path'], file_name='user_info.json') self.__position_record = io_util.read_config( file_path=config['config_path'], file_name='tiger_position_record.json') self.record = self.__position_record[account_type].copy() self.eod_api_key = config['api_key']['eod'] # set account, account type self.account = self.__user_info[account_type] self.account_type = account_type # initialize client_config self.client_config = TigerOpenClientConfig(sandbox_debug=sandbox_debug) self.client_config.private_key = read_private_key( config['tiger_path'] + self.__user_info['private_key_name']) self.client_config.tiger_id = str(self.__user_info['tiger_id']) self.client_config.language = Language.en_US self.client_config.account = self.account # get quote/trade clients, assets, positions self.quote_client = QuoteClient(self.client_config) self.trade_client = TradeClient(self.client_config) self.positions = self.trade_client.get_positions(account=self.account) self.assets = self.trade_client.get_assets(account=self.account) # get market status and trade time self.update_trade_time(open_time_adj=open_time_adj, close_time_adj=close_time_adj) # update position record self.synchronize_position_record(config=config) self.logger.info(f'[tiger]: Tiger instance created: {logger_name}')
def connect_trade(self): """ Connect to trade server. """ self.trade_client = TradeClient(self.client_config) try: self.add_task(self.query_order) self.add_task(self.query_position) self.add_task(self.query_account) except ApiException: self.write_log("交易接口连接失败") return self.write_log("交易接口连接成功")
def trade_apis(): account = client_config.account openapi_client = TradeClient(client_config, logger=logger) contract = openapi_client.get_contracts('AAPL')[0] order = openapi_client.create_order(account, contract, 'BUY', 'LMT', 100, limit_price=5.0) order_id = order.order_id openapi_client.place_order(order) new_order = openapi_client.get_order(order.order_id) assert order.order_id == new_order.order_id openapi_client.modify_order(new_order, quantity=150) new_order = openapi_client.get_order(order_id) assert new_order.quantity == 150 openapi_client.cancel_order(order_id) new_order = openapi_client.get_order(order_id) assert new_order.status == ORDER_STATUS.CANCELLED or new_order.status == ORDER_STATUS.PENDING_CANCEL
def get_trade_apis(): client_config = get_client_config() trade_client = TradeClient(client_config) trade_client.get_managed_accounts()
def trade_apis(): account = client_config.account openapi_client = TradeClient(client_config, logger=logger) # 通过请求获取合约 contract = openapi_client.get_contracts('AAPL')[0] # contract = openapi_client.get_contract('AAPL', SecurityType.STK, currency=Currency.USD) # 本地构造合约 # stock 股票 # contract = stock_contract(symbol='AAPL', currency='USD') # option 期权 # contract = option_contract(identifier='AAPL 190118P00160000') # contract = option_contract_by_symbol('AAPL', '20200110', strike=280.0, put_call='PUT', currency='USD') # future 期货 # contract = future_contract('CHF', 'USD', '20190617', multiplier=125000, exchange='GLOBEX') # war 港股窝轮 # contract = war_contract_by_symbol('02318', '20200326', 107.08, 'CALL', local_symbol='12616', currency='HKD') # iopt 港股牛熊证 # contract = iopt_contract_by_symbol('02318', '20200420', 87.4, 'CALL', local_symbol='63379', currency='HKD') order = openapi_client.create_order(account, contract, 'BUY', 'LMT', 100, limit_price=5.0) # 或者本地构造订单对象 # order = limit_order(account=account, contract=contract, action='BUY', quantity=100, limit_price=5.0) openapi_client.place_order(order) new_order = openapi_client.get_order(id=order.id) assert order.order_id == new_order.order_id openapi_client.modify_order(new_order, quantity=150) new_order = openapi_client.get_order(id=order.id) assert new_order.quantity == 150 openapi_client.cancel_order(id=order.id) new_order = openapi_client.get_order(id=order.id) assert new_order.status == OrderStatus.CANCELLED or new_order.status == OrderStatus.PENDING_CANCEL # 预览订单 (下单前后保证金要求, 佣金等预览) result = openapi_client.preview_order(order) print(result) # 限价单 + 附加订单 (仅主订单为限价单时支持附加订单) stop_loss_order_leg = order_leg('LOSS', 8.0, time_in_force='GTC') # 附加止损 profit_taker_order_leg = order_leg('PROFIT', 12.0, time_in_force='GTC') # 附加止盈 main_order = openapi_client.create_order(account, contract, 'BUY', 'LMT', quantity=100, limit_price=10.0, order_legs=[stop_loss_order_leg, profit_taker_order_leg]) # 本地构造限价单 + 附加订单 # main_order = limit_order_with_legs(account, contract, 'BUY', 100, limit_price=10.0, # order_legs=[stop_loss_order_leg]) openapi_client.place_order(main_order) print(main_order) # 查询主订单所关联的附加订单 order_legs = openapi_client.get_open_orders(account, parent_id=main_order.order_id) print(order_legs)
def get_account_apis(): openapi_client = TradeClient(client_config, logger=logger) openapi_client.get_managed_accounts() # 获取订单 openapi_client.get_orders() # 获取未成交订单 # openapi_client.get_open_orders() # 获取已成交订单 # openapi_client.get_filled_orders(start_time='2019-05-01', end_time='2019-05-21') # 获取订单成交记录, 仅适用于综合账户 transactions = openapi_client.get_transactions(symbol='AAPL', sec_type=SecurityType.STK, start_time=1641398400000, end_time=1642398400000) # transactions = openapi_client.get_transactions(symbol='CL2201', sec_type=SecurityType.FUT) # transactions = openapi_client.get_transactions(order_id=24844739769009152) # transactions = openapi_client.get_transactions(symbol='BABA', sec_type='OPT', strike=121, expiry='20220121', # put_call='CALL') # 获取持仓 openapi_client.get_positions() # 获取资产 openapi_client.get_assets() # 综合/模拟账户获取资产 openapi_client.get_prime_assets()
class Tiger: # default logger defualt_logger = logging.getLogger('bc_tiger_logger') # init def __init__(self, account_type, config, sandbox_debug=False, logger_name=None, open_time_adj=0, close_time_adj=0): # get logger self.logger = Tiger.defualt_logger if ( logger_name is None) else logging.getLogger(logger_name) # read user info, position record from local files self.__user_info = io_util.read_config(file_path=config['tiger_path'], file_name='user_info.json') self.__position_record = io_util.read_config( file_path=config['config_path'], file_name='tiger_position_record.json') self.record = self.__position_record[account_type].copy() self.eod_api_key = config['api_key']['eod'] # set account, account type self.account = self.__user_info[account_type] self.account_type = account_type # initialize client_config self.client_config = TigerOpenClientConfig(sandbox_debug=sandbox_debug) self.client_config.private_key = read_private_key( config['tiger_path'] + self.__user_info['private_key_name']) self.client_config.tiger_id = str(self.__user_info['tiger_id']) self.client_config.language = Language.en_US self.client_config.account = self.account # get quote/trade clients, assets, positions self.quote_client = QuoteClient(self.client_config) self.trade_client = TradeClient(self.client_config) self.positions = self.trade_client.get_positions(account=self.account) self.assets = self.trade_client.get_assets(account=self.account) # get market status and trade time self.update_trade_time(open_time_adj=open_time_adj, close_time_adj=close_time_adj) # update position record self.synchronize_position_record(config=config) self.logger.info(f'[tiger]: Tiger instance created: {logger_name}') # get user info def get_user_info(self): return self.__user_info # get position record def get_position_record(self): return self.__position_record # synchronize position record with real position status def synchronize_position_record(self, config): account_type = self.account_type # initialize position record for symbols that not in position record init_cash = config['trade']['init_cash'][account_type] pool = config['selected_sec_list'][config['trade']['pool'] [account_type]] for symbol in pool: if symbol not in self.record.keys(): self.record[symbol] = {'cash': init_cash, 'position': 0} # get real position (dict) position_dict = dict([(x.contract.symbol, x.quantity) for x in self.positions]) # compare position record with real position record_conflicted = False for symbol in self.record.keys(): if symbol not in pool: continue # update position in record record_position = self.record[symbol]['position'] current_position = 0 if ( symbol not in position_dict.keys()) else position_dict[symbol] if current_position != record_position: record_conflicted = True if current_position > 0: self.record[symbol] = { 'cash': 0, 'position': current_position } else: self.record[symbol] = {'cash': init_cash, 'position': 0} self.logger.error( f'[{account_type[:4]}]: {symbol} position({current_position}) rather than ({record_position}), reset record' ) # add record for position that not recorded for symbol in [ x for x in position_dict.keys() if (x in pool and x not in self.record.keys()) ]: record_conflicted = True self.record[symbol] = { 'cash': 0, 'position': position_dict[symbol] } self.logger.error( f'[{account_type[:4]}]: {symbol} position({position_dict[symbol]}) not in record, add record' ) # update __position_record if record_conflicted: self.__position_record[self.account_type] = self.record.copy() io_util.create_config_file(config_dict=self.__position_record, file_path=config['config_path'], file_name='tiger_position_record.json') # update position for an account def update_position_record(self, config, init_cash=None, init_position=None, start_time=None, end_time=None, is_print=True): # set default values init_cash = config['trade']['init_cash'][self.account_type] if ( init_cash is None) else init_cash init_position = 0 if (init_position is None) else init_position start_time = self.trade_time['pre_open_time'].strftime( format="%Y-%m-%d %H:%M:%S") if (start_time is None) else start_time end_time = self.trade_time['post_close_time'].strftime( format="%Y-%m-%d %H:%M:%S") if (end_time is None) else end_time try: # get today filled orders orders = self.trade_client.get_filled_orders(start_time=start_time, end_time=end_time) # update position records for order in orders: symbol = order.contract.symbol action = order.action quantity = order.quantity - order.remaining commission = order.commission avg_fill_price = order.avg_fill_price # init record if not exist if symbol not in self.record.keys(): self.record[symbol] = { 'cash': init_cash, 'position': init_position } record_cash = self.record[symbol]['cash'] record_position = self.record[symbol]['position'] # calculate new cash and position if action == 'BUY': cost = avg_fill_price * quantity + commission new_cash = record_cash - cost new_position = record_position + quantity elif action == 'SELL': acquire = avg_fill_price * quantity - commission new_cash = record_cash + acquire new_position = record_position - quantity else: new_cash = record_cash new_position = record_position # update record if new_cash >= 0 and new_position >= 0: self.record[symbol]['cash'] = new_cash self.record[symbol]['position'] = new_position if is_print: self.logger.info( f'[{self.account_type[:4]}]: updating position record for {symbol} {record_cash, record_position} -> {new_cash, new_position}' ) # update __position_record # self.record['updated'] = datetime.datetime.now().strftime(format="%Y-%m-%d %H:%M:%S") self.__position_record = io_util.read_config( file_path=config['config_path'], file_name='tiger_position_record.json') self.__position_record[self.account_type] = self.record.copy() self.__position_record['updated'][ self.account_type] = datetime.datetime.now().strftime( format="%Y-%m-%d %H:%M:%S") io_util.create_config_file(config_dict=self.__position_record, file_path=config['config_path'], file_name='tiger_position_record.json') except Exception as e: self.logger.exception( f'[erro]: fail updating position records for {self.account_type}, {e}' ) # update portfolio for an account def update_portfolio_record(self, config, position_summary=None, is_print=True): # get position summary if position_summary is None: position_summary = self.get_position_summary(get_briefs=False) position_summary.set_index('symbol', inplace=True) position_summary = position_summary.round(2) # get asset summary net_value = 0 market_value = 0 cash = 0 asset_summary = self.get_asset_summary() if len(asset_summary) > 0: net_value = asset_summary.loc[0, 'net_value'] market_value = asset_summary.loc[0, 'holding_value'] cash = asset_summary.loc[0, 'cash'] # post process if market_value == float('inf'): market_value = position_summary['market_value'].sum().round(2) # load portfolio record portfolio_record = io_util.read_config(file_path=config['config_path'], file_name='portfolio.json') old_net_value = portfolio_record['tiger'][self.account_type].get( 'net_value') support = portfolio_record['tiger'][self.account_type].get( 'portfolio').get('support') resistant = portfolio_record['tiger'][self.account_type].get( 'portfolio').get('resistant') # update portfolio record for current account portfolio_record['tiger'][ self.account_type]['portfolio'] = position_summary.to_dict() portfolio_record['tiger'][ self.account_type]['portfolio']['support'] = {} portfolio_record['tiger'][ self.account_type]['portfolio']['resistant'] = {} quantity = portfolio_record['tiger'][ self.account_type]['portfolio'].get('quantity') if quantity is not None: if support is not None: for symbol in quantity.keys(): portfolio_record['tiger'][self.account_type]['portfolio'][ 'support'][symbol] = support.get(symbol) if resistant is not None: for symbol in quantity.keys(): portfolio_record['tiger'][self.account_type]['portfolio'][ 'resistant'][symbol] = resistant.get(symbol) portfolio_record['tiger'][ self.account_type]['market_value'] = market_value portfolio_record['tiger'][self.account_type]['net_value'] = net_value portfolio_record['tiger'][self.account_type]['cash'] = cash portfolio_record['tiger'][ self.account_type]['updated'] = datetime.datetime.now().strftime( format="%Y-%m-%d %H:%M:%S") io_util.create_config_file(config_dict=portfolio_record, file_path=config['config_path'], file_name='portfolio.json') # print if is_print: self.logger.info( f'[{self.account_type[:4]}]: net value {old_net_value} --> {net_value}' ) # get summary of positions def get_position_summary(self, get_briefs=False): try: # update positions self.positions = self.trade_client.get_positions( account=self.client_config.account) # convert positions(list) to dataframe if len(self.positions) > 0: result = { 'symbol': [], 'quantity': [], 'average_cost': [], 'market_price': [] } for pos in self.positions: result['symbol'].append(pos.contract.symbol) result['quantity'].append(pos.quantity) result['average_cost'].append(pos.average_cost) result['market_price'].append(pos.market_price) result = pd.DataFrame(result) # get briefs for stocks in positions if get_briefs: status = io_util.get_stock_briefs( symbols=[x.contract.symbol for x in self.positions], source='eod', period='1d', interval='1m', api_key=self.eod_api_key) result = pd.merge(result, status, how='left', left_on='symbol', right_on='symbol') result['rate'] = round( (result['latest_price'] - result['average_cost']) / result['average_cost'], 2) result = result[[ 'symbol', 'quantity', 'average_cost', 'latest_price', 'rate', 'latest_time' ]] else: result.rename(columns={'market_price': 'latest_price'}, inplace=True) result['rate'] = round( (result['latest_price'] - result['average_cost']) / result['average_cost'], 2) result['latest_time'] = None # calculate market value result['market_value'] = result['quantity'] * result[ 'latest_price'] else: result = pd.DataFrame({ 'symbol': [], 'quantity': [], 'average_cost': [], 'latest_price': [], 'rate': [], 'market_value': [], 'latest_time': [] }) except Exception as e: result = pd.DataFrame({ 'symbol': [], 'quantity': [], 'average_cost': [], 'latest_price': [], 'rate': [], 'market_value': [], 'latest_time': [] }) self.logger.exception(f'[erro]: can not get position summary: {e}') return result # get summary of assets def get_asset_summary(self, print_summary=False): # update assets self.assets = self.trade_client.get_assets( account=self.client_config.account) asset = self.assets[0] result = { 'account': [asset.account], 'net_value': [asset.summary.net_liquidation], 'holding_value': [asset.summary.gross_position_value], 'cash': [asset.summary.cash], 'available_casg': [asset.summary.available_funds], 'pnl': [asset.summary.realized_pnl], 'holding_pnl': [asset.summary.unrealized_pnl] } if print_summary: summary = f''' 账户: {asset.account}({asset.summary.currency}): 总资产: {asset.summary.net_liquidation} 现金: {asset.summary.cash} (可用 {asset.summary.available_funds}) 持仓市值: {asset.summary.gross_position_value} 日内交易次数: {asset.summary.day_trades_remaining} 已实现盈亏: {asset.summary.realized_pnl} 未实现盈亏: {asset.summary.unrealized_pnl} ''' print(summary) return pd.DataFrame(result) # get available money def get_available_cash(self): # get available cash for real accounts self.assets = self.trade_client.get_assets( account=self.client_config.account) available_cash = self.assets[0].summary.cash return available_cash # get quantity of symbol currently in the position def get_in_position_quantity(self, symbol, get_briefs=False): # initialize affordable quantity quantity = 0 # get position summary position = self.get_position_summary(get_briefs=get_briefs) if len(position) > 0: position = position.set_index('symbol') if symbol in position.index: quantity = position.loc[symbol, 'quantity'] return quantity # check whether it is affordable to buy certain amount of a stock def get_affordable_quantity(self, symbol, cash=None, trading_fee=3): # initialize affordable quantity and available cash quantity = 0 available_cash = self.get_available_cash() if (cash is None) else cash # get latest price of stock stock_brief = io_util.get_stock_briefs( symbols=[symbol], source='eod', period='1d', interval='1m', api_key=self.eod_api_key).set_index('symbol') latest_price = stock_brief.loc[symbol, 'latest_price'] # check if it is affordable quantity = math.floor((available_cash - trading_fee) / latest_price) return quantity # idle for specified time and check position in certain frequency def idle(self, target_time, check_frequency=600): """ Sleep with a fixed frequency, until the target time :param target_time: the target time in datetime.datetime format :param check_frequency: the fixed sleep_time :returns: none :raises: none """ # get current time now = datetime.datetime.now() while now < target_time: # # get position summary # pos = self.get_position_summary() # self.logger.info(f'[rate]:----------------------------------------------\n{pos}\n') # get current time, calculate difference between current time and target time diff_time = round((target_time - now).total_seconds()) sleep_time = (diff_time + 1) if ( diff_time <= check_frequency) else check_frequency # sleep self.logger.info( f'[idle]: {now.strftime(format="%Y-%m-%d %H:%M:%S")}: sleep for {sleep_time} seconds' ) time.sleep(sleep_time) # update current time now = datetime.datetime.now() self.logger.info( f'[wake]: {now.strftime(format="%Y-%m-%d %H:%M:%S")}: exceed target time({target_time})' ) # update trade time def update_trade_time(self, market=Market.US, tz='Asia/Shanghai', open_time_adj=0, close_time_adj=0): # get local timezone tz = pytz.timezone(tz) try: # get open_time status = self.quote_client.get_market_status(market=market)[0] current_status = status.status open_time = status.open_time.astimezone(tz).replace(tzinfo=None) open_time = open_time + datetime.timedelta(hours=open_time_adj) # if program runs after market open, api will return trade time for next trade day, # trade time for current trade day need to be calculated manually if status.status in ['Trading', 'Post-Market Trading']: if open_time.weekday() == 0: open_time = open_time - datetime.timedelta(days=3) else: open_time = open_time - datetime.timedelta(days=1) # calculate close time, pre_open_time, post_close_time close_time = open_time + datetime.timedelta(hours=6.5 + close_time_adj) pre_open_time = open_time - datetime.timedelta(hours=5.5) post_close_time = close_time + datetime.timedelta(hours=4) # open and close time of chinese stock market a_open_time = pre_open_time + datetime.timedelta( hours=9.5 - pre_open_time.hour) a_close_time = pre_open_time + datetime.timedelta( hours=15 - pre_open_time.hour) except Exception as e: self.logger.error(e) current_status = None open_time = None close_time = None pre_open_time = None post_close_time = None self.trade_time = { 'status': current_status, 'tz': tz, 'pre_open_time': pre_open_time, 'open_time': open_time, 'close_time': close_time, 'post_close_time': post_close_time, 'a_open_time': a_open_time, 'a_close_time': a_close_time } # update market status def update_market_status(self, market=Market.US, return_str=False): try: # get market status status = self.quote_client.get_market_status(market=market)[0] self.trade_time['status'] = status.status if return_str: time_format = '%Y-%m-%d %H:%M' pre_open_time = self.trade_time['pre_open_time'].strftime( time_format) post_close_time = self.trade_time['post_close_time'].strftime( time_format) time_format = '%H:%M' open_time = self.trade_time['open_time'].strftime(time_format) close_time = self.trade_time['close_time'].strftime( time_format) time_str = f'<({pre_open_time}){open_time} -- {close_time}({post_close_time})>' return time_str except Exception as e: self.logger.error(e) # buy or sell stocks def trade(self, symbol, action, quantity, price=None, stop_loss=None, stop_profit=None, print_summary=True): trade_summary = '' try: # construct contract contract = stock_contract(symbol=symbol, currency='USD') # construct order if price is None: order_price = 'market' order = market_order(account=self.client_config.account, contract=contract, action=action, quantity=quantity) else: order_price = float(f'{price}') order = limit_order(account=self.client_config.account, contract=contract, action=action, quantity=quantity, limit_price=price) # construct trade summary trade_summary += f'[{action}]: {symbol} X {quantity} ({order_price})\t' # attach order legs order_legs = [] if stop_loss is not None: stop_loss_order_leg = order_leg('LOSS', stop_loss, time_in_force='GTC') # 附加止损单 order_legs.append(stop_loss_order_leg) if stop_profit is not None: stop_profit_order_leg = order_leg('PROFIT', stop_profit, time_in_force='GTC') # 附加止盈单 order_legs.append(stop_profit_order_leg) if len(order_legs) > 0: order.order_legs = order_legs # place buy order if affordable if action == 'BUY': affordable_quantity = self.get_affordable_quantity( symbol=symbol) if quantity <= affordable_quantity: self.trade_client.place_order(order) trade_summary += f'SUCCEED: {order.id}' else: trade_summary += f'FAILED: Not affordable({affordable_quantity}/{quantity})' # place sell order if holding enough stocks elif action == 'SELL': in_position_quantity = self.get_in_position_quantity(symbol) if in_position_quantity >= quantity: self.trade_client.place_order(order) trade_summary += f'SUCCEED: {order.id}' else: trade_summary += f'FAILED: Not enough stock to sell({in_position_quantity}/{quantity})' # other actions else: trade_summary += f'FAILED: Unknown action({action})' except Exception as e: trade_summary += f'FAILED: {e}' # print trade summary if print_summary: self.logger.info(trade_summary) return trade_summary # auto trade according to signals def signal_trade(self, signal, money_per_sec, order_type='market', trading_fee=5, pool=None, according_to_record=True, minimum_position=None): # set symbol to index if len(signal) > 0: # signal = signal.rename(columns={'代码':'symbol', '交易信号':'action'}) # signal = signal.set_index('symbol') # filter sec with pool if pool is not None: filtered_list = [x for x in signal.index if x in pool] signal = signal.loc[filtered_list, signal.columns].copy() # if signal list is not empty if len(signal) > 0: # get latest price for signals # if order_type == 'market': # signal_brief = self.quote_client.get_stock_briefs(symbols=signal.index.tolist()).set_index('symbol') # signal_brief = io_util.get_stock_briefs(symbols=signal.index.tolist(), source='eod', period='1d', interval='1m', api_key=self.eod_api_key).set_index('symbol') # signal = pd.merge(signal, signal_brief[['latest_price']], how='left', left_index=True, right_index=True) # get in-position quantity and latest price for signals position = self.get_position_summary(get_briefs=False) if len(position) == 0: position = pd.DataFrame({'symbol': [], 'quantity': []}) position = position.set_index('symbol') signal = pd.merge(signal, position[['quantity']], how='left', left_index=True, right_index=True).fillna(0) # sell # get sell signals sell_signal = signal.query('action == "s"') if len(sell_signal) > 0: # go through sell signals for symbol in sell_signal.index: # check whether symbol is in positions in_position_quantity = signal.loc[symbol, 'quantity'] if in_position_quantity > 0: if order_type == 'limit': price = signal.loc[symbol, 'latest_price'] else: price = None trade_summary = self.trade( symbol=symbol, action='SELL', quantity=in_position_quantity, price=price, print_summary=False) self.logger.info(trade_summary) else: self.logger.info( f'[SELL]: {symbol} skipped (not in positions)') else: self.logger.info(f'[SELL]: no signal') # buy # get available cash, set minimum position available_cash = self.get_available_cash() if minimum_position is None: minimum_position = money_per_sec # get buy signals which not in posiitons yet default_money_per_sec = money_per_sec buy_signal = signal.query('action == "b"') if len(buy_signal) > 0: # go through buy signals for symbol in buy_signal.index: # break when available cash is below 200 if available_cash <= minimum_position: self.logger.info( f'[BUY]: Available cash is too low({available_cash}/{minimum_position}), stop buying' ) break # check whether symbol is already in positions in_position_quantity = signal.loc[symbol, 'quantity'] if in_position_quantity == 0: # set money used to establish a new position if according_to_record: if (symbol in self.record.keys()) and ( self.record[symbol]['position'] == 0): money_per_sec = self.record[symbol]['cash'] else: money_per_sec = default_money_per_sec # check whether there is enough available money money_per_sec = available_cash if ( money_per_sec > available_cash) else money_per_sec # calculate quantity to buy quantity = math.floor( (money_per_sec - trading_fee) / signal.loc[symbol, 'latest_price']) if quantity > 0: if order_type == 'limit': price = signal.loc[symbol, 'latest_price'] else: price = None trade_summary = self.trade(symbol=symbol, action='BUY', quantity=quantity, price=price, print_summary=False) self.logger.info(trade_summary) # update available cash available_cash -= quantity * signal.loc[ symbol, 'latest_price'] else: self.logger.info(f'[BUY]: not enough money') continue else: self.logger.info( f'[BUY]: {symbol} skipped (already in positions:{in_position_quantity})' ) continue else: self.logger.info(f'[BUY]: no signal') else: self.logger.info(f'[SKIP]: no signal') # stop loss or stop profit or clear all positions def cash_out(self, stop_loss_rate=None, stop_profit_rate=None, clear_all=False, print_summary=True): # get current position with summary position = self.get_position_summary(get_briefs=True) if len(position) > 0: # set symbol as index position = position.set_index('symbol') # if clear all positions if clear_all: cash_out_list = position.index.tolist() else: stop_loss_list = [] if stop_loss_rate is None else position.query( f'rate < {stop_loss_rate}').index.tolist() stop_profit_list = [] if stop_profit_rate is None else position.query( f'rate > {stop_profit_rate}').index.tolist() cash_out_list = list(set(stop_loss_list + stop_profit_list)) # cash out if len(cash_out_list) > 0: cash_out_position = position.loc[cash_out_list, ].copy() self.logger.info( f'[STOP]: LOSS: {stop_loss_list}, PROFIT: {stop_profit_list}' ) for index, row in cash_out_position.iterrows(): self.trade(symbol=index, action='SELL', quantity=row['quantity'], print_summary=print_summary)
class TigerGateway(BaseGateway): """""" default_setting = { "tiger_id": "", "account": "", " server ": [" standard ", " global ", " simulation "], "private_key": "", } exchanges = [Exchange.SEHK, Exchange.SMART, Exchange.SSE, Exchange.SZSE] def __init__(self, event_engine): """Constructor""" super(TigerGateway, self).__init__(event_engine, "TIGER") self.tiger_id = "" self.account = "" self.server = "" self.language = "" self.client_config = None self.quote_client = None self.push_client = None self.local_id = 1000000 self.tradeid = 0 self.active = False self.queue = Queue() self.pool = None self.ID_TIGER2VT = {} self.ID_VT2TIGER = {} self.ticks = {} self.trades = set() self.contracts = {} self.symbol_names = {} self.push_connected = False self.subscribed_symbols = set() def run(self): """""" while self.active: try: func, args = self.queue.get(timeout=0.1) func(*args) except Empty: pass def add_task(self, func, *args): """""" self.queue.put((func, [*args])) def connect(self, setting: dict): """""" self.private_key = setting["private_key"] self.tiger_id = setting["tiger_id"] self.server = setting[" server "] self.account = setting["account"] self.languege = Language.zh_CN # Start thread pool for REST call self.active = True self.pool = Pool(5) self.pool.apply_async(self.run) # Put connect task into quque. self.init_client_config() self.add_task(self.connect_quote) self.add_task(self.connect_trade) self.add_task(self.connect_push) def init_client_config(self, sandbox=False): """""" self.client_config = TigerOpenClientConfig(sandbox_debug=sandbox) self.client_config.private_key = self.private_key self.client_config.tiger_id = self.tiger_id self.client_config.account = self.account self.client_config.language = self.language def connect_quote(self): """ Connect to market data server. """ try: self.quote_client = QuoteClient(self.client_config) self.symbol_names = dict( self.quote_client.get_symbol_names(lang=Language.zh_CN)) self.query_contract() except ApiException: self.write_log(" queries contract failure ") return self.write_log(" quotes interfacing success ") self.write_log(" contract query succeeds ") def connect_trade(self): """ Connect to trade server. """ self.trade_client = TradeClient(self.client_config) try: self.add_task(self.query_order) self.add_task(self.query_position) self.add_task(self.query_account) except ApiException: self.write_log(" transaction interface connection failure ") return self.write_log(" successful transaction interface ") def connect_push(self): """ Connect to push server. """ protocol, host, port = self.client_config.socket_host_port self.push_client = PushClient(host, port, (protocol == "ssl")) self.push_client.quote_changed = self.on_quote_change self.push_client.asset_changed = self.on_asset_change self.push_client.position_changed = self.on_position_change self.push_client.order_changed = self.on_order_change self.push_client.connect_callback = self.on_push_connected self.push_client.connect(self.client_config.tiger_id, self.client_config.private_key) def subscribe(self, req: SubscribeRequest): """""" self.subscribed_symbols.add(req.symbol) if self.push_connected: self.push_client.subscribe_quote([req.symbol]) def on_push_connected(self): """""" self.push_connected = True self.write_log(" push interfacing success ") self.push_client.subscribe_asset() self.push_client.subscribe_position() self.push_client.subscribe_order() self.push_client.subscribe_quote(list(self.subscribed_symbols)) def on_quote_change(self, tiger_symbol: str, data: list, trading: bool): """""" data = dict(data) symbol, exchange = convert_symbol_tiger2vt(tiger_symbol) tick = self.ticks.get(symbol, None) if not tick: tick = TickData( symbol=symbol, exchange=exchange, gateway_name=self.gateway_name, datetime=datetime.now(), name=self.symbol_names[symbol], ) self.ticks[symbol] = tick tick.datetime = datetime.fromtimestamp(int(data["timestamp"]) / 1000) tick.pre_close = data.get("prev_close", tick.pre_close) tick.last_price = data.get("latest_price", tick.last_price) tick.volume = data.get("volume", tick.volume) tick.open_price = data.get("open", tick.open_price) tick.high_price = data.get("high", tick.high_price) tick.low_price = data.get("low", tick.low_price) tick.ask_price_1 = data.get("ask_price", tick.ask_price_1) tick.bid_price_1 = data.get("bid_price", tick.bid_price_1) tick.ask_volume_1 = data.get("ask_size", tick.ask_volume_1) tick.bid_volume_1 = data.get("bid_size", tick.bid_volume_1) self.on_tick(copy(tick)) def on_asset_change(self, tiger_account: str, data: list): """""" data = dict(data) if "net_liquidation" not in data: return account = AccountData( accountid=tiger_account, balance=data["net_liquidation"], frozen=0.0, gateway_name=self.gateway_name, ) self.on_account(account) def on_position_change(self, tiger_account: str, data: list): """""" data = dict(data) symbol, exchange = convert_symbol_tiger2vt(data["origin_symbol"]) pos = PositionData( symbol=symbol, exchange=exchange, direction=Direction.NET, volume=int(data["quantity"]), frozen=0.0, price=data["average_cost"], pnl=data["unrealized_pnl"], gateway_name=self.gateway_name, ) self.on_position(pos) def on_order_change(self, tiger_account: str, data: list): """""" data = dict(data) symbol, exchange = convert_symbol_tiger2vt(data["origin_symbol"]) status = STATUS_TIGER2VT[data["status"]] order = OrderData( symbol=symbol, exchange=exchange, orderid=self.ID_TIGER2VT.get(str(data["order_id"]), self.get_new_local_id()), direction=Direction.NET, price=data.get("limit_price", 0), volume=data["quantity"], traded=data["filled"], status=status, time=datetime.fromtimestamp(data["order_time"] / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.ID_TIGER2VT[str(data["order_id"])] = order.orderid self.on_order(order) if status == Status.ALLTRADED: self.tradeid += 1 trade = TradeData( symbol=symbol, exchange=exchange, direction=Direction.NET, tradeid=self.tradeid, orderid=self.ID_TIGER2VT[str(data["order_id"])], price=data["avg_fill_price"], volume=data["filled"], time=datetime.fromtimestamp(data["trade_time"] / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_trade(trade) def get_new_local_id(self): self.local_id += 1 return self.local_id def send_order(self, req: OrderRequest): """""" local_id = self.get_new_local_id() order = req.create_order_data(local_id, self.gateway_name) self.on_order(order) self.add_task(self._send_order, req, local_id) return order.vt_orderid def _send_order(self, req: OrderRequest, local_id): """""" currency = config_symbol_currency(req.symbol) try: contract = self.trade_client.get_contracts(symbol=req.symbol, currency=currency)[0] order = self.trade_client.create_order( account=self.account, contract=contract, action=DIRECTION_VT2TIGER[req.direction], order_type=ORDERTYPE_VT2TIGER[req.type], quantity=int(req.volume), limit_price=req.price, ) self.ID_TIGER2VT[str(order.order_id)] = local_id self.ID_VT2TIGER[local_id] = str(order.order_id) self.trade_client.place_order(order) except: # noqa traceback.print_exc() self.write_log(" billed failure ") return def cancel_order(self, req: CancelRequest): """""" self.add_task(self._cancel_order, req) def _cancel_order(self, req: CancelRequest): """""" try: order_id = self.ID_VT2TIGER[req.orderid] data = self.trade_client.cancel_order(order_id=order_id) except ApiException: self.write_log(f" withdrawals failure :{req.orderid}") if not data: self.write_log(" withdrawals success ") def query_contract(self): """""" # HK Stock symbols_names_HK = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.HK) contract_names_HK = DataFrame(symbols_names_HK, columns=["symbol", "name"]) contractList = list(contract_names_HK["symbol"]) i, n = 0, len(contractList) result = pd.DataFrame() while i < n: i += 50 c = contractList[i - 50:i] r = self.quote_client.get_trade_metas(c) result = result.append(r) contract_detail_HK = result.sort_values(by="symbol", ascending=True) contract_HK = pd.merge(contract_names_HK, contract_detail_HK, how="left", on="symbol") for ix, row in contract_HK.iterrows(): contract = ContractData( symbol=row["symbol"], exchange=Exchange.SEHK, name=row["name"], product=Product.EQUITY, size=1, min_volume=row["lot_size"], pricetick=row["min_tick"], net_position=True, gateway_name=self.gateway_name, ) self.on_contract(contract) self.contracts[contract.vt_symbol] = contract # US Stock symbols_names_US = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.US) contract_US = DataFrame(symbols_names_US, columns=["symbol", "name"]) for ix, row in contract_US.iterrows(): contract = ContractData( symbol=row["symbol"], exchange=Exchange.SMART, name=row["name"], product=Product.EQUITY, size=1, min_volume=100, pricetick=0.001, gateway_name=self.gateway_name, ) self.on_contract(contract) self.contracts[contract.vt_symbol] = contract # CN Stock symbols_names_CN = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.CN) contract_CN = DataFrame(symbols_names_CN, columns=["symbol", "name"]) for ix, row in contract_CN.iterrows(): symbol = row["symbol"] symbol, exchange = convert_symbol_tiger2vt(symbol) contract = ContractData( symbol=symbol, exchange=exchange, name=row["name"], product=Product.EQUITY, size=1, min_volume=100, pricetick=0.001, gateway_name=self.gateway_name, ) self.on_contract(contract) self.contracts[contract.vt_symbol] = contract def query_account(self): """""" try: assets = self.trade_client.get_assets() except ApiException: self.write_log(" queries funds fail ") return for i in assets: account = AccountData( accountid=self.account, balance=i.summary.net_liquidation, frozen=0.0, gateway_name=self.gateway_name, ) self.on_account(account) def query_position(self): """""" try: position = self.trade_client.get_positions() except ApiException: self.write_log(" queries positions fail ") return for i in position: symbol, exchange = convert_symbol_tiger2vt(i.contract.symbol) pos = PositionData( symbol=symbol, exchange=exchange, direction=Direction.NET, volume=int(i.quantity), frozen=0.0, price=i.average_cost, pnl=float(i.unrealized_pnl), gateway_name=self.gateway_name, ) self.on_position(pos) def query_order(self): """""" try: data = self.trade_client.get_orders() data = sorted(data, key=lambda x: x.order_time, reverse=False) except: # noqa traceback.print_exc() self.write_log(" inquiry commission failed ") return self.process_order(data) self.process_deal(data) def close(self): """""" self.active = False if self.push_client: self.push_client.disconnect() def process_order(self, data): """""" for i in data: symbol, exchange = convert_symbol_tiger2vt(str(i.contract)) local_id = self.get_new_local_id() order = OrderData( symbol=symbol, exchange=exchange, orderid=local_id, direction=Direction.NET, price=i.limit_price if i.limit_price else 0.0, volume=i.quantity, traded=i.filled, status=STATUS_TIGER2VT[i.status], time=datetime.fromtimestamp(i.order_time / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.ID_TIGER2VT[str(i.order_id)] = local_id self.on_order(order) self.ID_VT2TIGER = {v: k for k, v in self.ID_TIGER2VT.items()} def process_deal(self, data): """ Process trade data for both query and update. """ for i in data: if i.status == OrderStatus.PARTIALLY_FILLED or i.status == OrderStatus.FILLED: symbol, exchange = convert_symbol_tiger2vt(str(i.contract)) self.tradeid += 1 trade = TradeData( symbol=symbol, exchange=exchange, direction=Direction.NET, tradeid=self.tradeid, orderid=self.ID_TIGER2VT[str(i.order_id)], price=i.avg_fill_price, volume=i.filled, time=datetime.fromtimestamp(i.trade_time / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_trade(trade)
def trade_apis(): account = client_config.account openapi_client = TradeClient(client_config, logger=logger) # stock contract = openapi_client.get_contracts('AAPL')[0] # 或者本地构造合约对象 # contract = stock_contract(symbol='AAPL', currency='USD') # option # contract = option_contract(identifier='AAPL 190118P00160000') # future # contract = future_contract('CHF', 'USD', '20190617', multiplier=125000, exchange='GLOBEX') order = openapi_client.create_order(account, contract, 'BUY', 'LMT', 100, limit_price=5.0) # 或者本地构造订单对象 # order = limit_order(account=account, contract=contract, action='BUY', quantity=100, limit_price=5.0) openapi_client.place_order(order) order_id = order.order_id # you can operate order via id too new_order = openapi_client.get_order(order_id=order.order_id) assert order.order_id == new_order.order_id openapi_client.modify_order(new_order, quantity=150) new_order = openapi_client.get_order(order_id=order_id) assert new_order.quantity == 150 openapi_client.cancel_order(order_id=order_id) new_order = openapi_client.get_order(order_id=order_id) assert new_order.status == OrderStatus.CANCELLED or new_order.status == OrderStatus.PENDING_CANCEL # 预览订单 (下单前后保证金要求, 佣金等预览) result = openapi_client.preview_order(order) print(result) # 限价单 + 附加订单 (仅主订单为限价单时支持附加订单) stop_loss_order_leg = order_leg('LOSS', 8.0, time_in_force='GTC') # 附加止损 profit_taker_order_leg = order_leg('PROFIT', 12.0, time_in_force='GTC') # 附加止盈 main_order = openapi_client.create_order( account, contract, 'BUY', 'LMT', quantity=100, limit_price=10.0, order_legs=[stop_loss_order_leg, profit_taker_order_leg]) # 本地构造限价单 + 附加订单 # main_order = limit_order_with_legs(account, contract, 'BUY', 100, limit_price=10.0, # order_legs=[stop_loss_order_leg]) openapi_client.place_order(main_order) print(main_order) # 查询主订单所关联的附加订单 order_legs = openapi_client.get_open_orders(account, parent_id=main_order.order_id) print(order_legs)
class Test: def __init__(self): self.client_config = get_client_config() self.trade_client = TradeClient(self.client_config) self.openapi_client = QuoteClient(self.client_config, logger=logger) # 初始化 pushclient protocol, host, port = self.client_config.socket_host_port self.push_client = PushClient(host, port, use_ssl=(protocol == 'ssl')) self.push_client.connect(self.client_config.tiger_id, self.client_config.private_key) def trade(self): stock = stock_contract(symbol='AAPL', currency='USD') option = option_contract(identifier='AAPL 190927P00200000') emu_account = [] # stock_contract = trade_client.get_contracts(symbol='FB')[0] account = self.trade_client.get_managed_accounts() print(account) emu_account = account[1] account = self.client_config.paper_account assets = self.trade_client.get_assets(account=account) print(assets) posinfo = self.trade_client.get_positions(account=account) print(posinfo) stock_order = market_order(account=account, # 下单账户,可以使用标准、环球、或模拟账户 contract = option, # 第1步中获取的合约对象 action = 'BUY', quantity = 1) print(stock_order) self.trade_client.place_order(stock_order) print(stock_order) # 直接本地构造contract对象。 期货 contract 的构造方法请参考后面的文档 def get_option_quote(self): symbol = 'AAPL' expirations = self.openapi_client.get_option_expirations(symbols=[symbol]) if len(expirations) > 1: print(expirations) expiry = int(expirations[expirations['symbol'] == symbol].at[0, 'timestamp']) chains = self.openapi_client.get_option_chain(symbol, expiry) print(chains) for index,row in chains.iterrows(): print(row["identifier"], row["strike"], row["put_call"]) briefs = self.openapi_client.get_option_briefs(['AAPL 190927P00200000']) print(briefs) bars = self.openapi_client.get_option_bars(['AAPL 190927P00200000']) print(bars) ticks = self.openapi_client.get_option_trade_ticks(['AAPL 190927P00200000']) print(ticks) for index,row in ticks.iterrows(): print(row["identifier"], row["time"], row["price"]) def on_quote_changed(self, symbol, items, hour_trading): print(symbol, items, hour_trading) def test1(self): info = app.openapi_client.get_briefs(symbols) print(info) def run(self): option_trade_ticks = self.openapi_client.get_option_trade_ticks(['AAPL 190927P00200000']) print(option_trade_ticks) def subscribe(self): # self.push_client.connect(self.client_config.tiger_id, self.client_config.private_key) self.push_client.quote_changed = self.on_quote_changed self.push_client.subscribe_quote(symbols=['AAPL 190927P00200000', 'GOOG', 'FB'], quote_key_type=QuoteKeyType.ALL) self.push_client.subscribe_asset() time.sleep(30) # self.push_client.unsubscribe_quote(['AAPL', 'GOOG']) def subscribe2(self): self.push_client.quote_changed = self.on_quote_changed self.push_client.subscribe_quote(symbols=['aapl'], quote_key_type=QuoteKeyType.ALL) self.push_client.subscribe_asset() def on_changed(self, symbol, items, hour_trading): print(symbol, items, hour_trading) data = dict(items) latest_price = data.get('latest_price') volume = data.get('volume') def query_subscribed(self): def on_subscribed_symbols(symbols, focus_keys, limit, used): print(symbols, focus_keys, limit, used) self.push_client.subscribed_symbols = on_subscribed_symbols self.push_client.query_subscribed_quote()
def trade_apis(): account = client_config.account openapi_client = TradeClient(client_config, logger=logger) # stock contract = openapi_client.get_contracts('AAPL')[0] # option # contract = option_contract(identifier='AAPL 190118P00160000') # future # contract = future_contract('CHF', 'USD', '20190617', multiplier=125000) # contract.exchange = 'GLOBEX' order = openapi_client.create_order(account, contract, 'BUY', 'LMT', 100, limit_price=0.1) order_id = order.order_id # you can operate order via id too openapi_client.place_order(order) new_order = openapi_client.get_order(order_id=order.order_id) assert order.order_id == new_order.order_id openapi_client.modify_order(new_order, quantity=150) new_order = openapi_client.get_order(order_id=order_id) assert new_order.quantity == 150 openapi_client.cancel_order(order_id=order_id) new_order = openapi_client.get_order(order_id=order_id) assert new_order.status == ORDER_STATUS.CANCELLED or new_order.status == ORDER_STATUS.PENDING_CANCEL
def get_trade_client(account='global_account'): client_config = get_client_config(account=account) trade_client = TradeClient(client_config) return trade_client
'STI', 'SIVB', 'SYMC', 'SYF', 'SNPS', 'SYY', 'TROW', 'TTWO', 'TPR', 'TGT', 'TEL', 'FTI', 'TXN', 'TXT', 'TMO', 'TIF', 'TWX', 'TJX', 'TMK', 'TSS', 'TSCO', 'TDG', 'TRV', 'TRIP', 'FOXA', 'FOX', 'TSN', 'UDR', 'ULTA', 'USB', 'UAA', 'UA', 'UNP', 'UAL', 'UNH', 'UPS', 'URI', 'UTX', 'UHS', 'UNM', 'VFC', 'VLO', 'VAR', 'VTR', 'VRSN', 'VRSK', 'VZ', 'VRTX', 'VIAB', 'V', 'VNO', 'VMC', 'WMT', 'WBA', 'DIS', 'WM', 'WAT', 'WEC', 'WFC', 'WELL', 'WDC', 'WU', 'WRK', 'WY', 'WHR', 'WMB', 'WLTW', 'WYN', 'WYNN', 'XEL', 'XRX', 'XLNX', 'XL', 'XYL', 'YUM', 'ZBH', 'ZION', 'ZTS' ] client_config = get_client_config(private_key_path=PRIVATE_KEY_PATH, tiger_id=TIGER_ID, account=ACCOUNT, sandbox_debug=True) quote_client = QuoteClient(client_config) trade_client = TradeClient(client_config) # 初始化 log 模块 logging.basicConfig( format='%(asctime)s - %(module)s - %(levelname)s - %(message)s', filename=LOG_PATH, filemode='a') log = logging.getLogger(__name__) log.setLevel(logging.INFO) def recorder(func): @wraps(func) def do_log(*args, **kwargs): try: log.info('func name is %s, args are %s, kwars are %s' %
def trade_apis(): account = client_config.account openapi_client = TradeClient(client_config, logger=logger) # stock contract = openapi_client.get_contracts('AAPL')[0] # 或者本地构造合约对象 # contract = stock_contract(symbol='AAPL', currency='USD') # option # contract = option_contract(identifier='AAPL 190118P00160000') # future # contract = future_contract('CHF', 'USD', '20190617', multiplier=125000, exchange='GLOBEX') order = openapi_client.create_order(account, contract, 'BUY', 'LMT', 100, limit_price=5.0) # 或者本地构造订单对象 # order = limit_order(account=account, contract=contract, action='BUY', quantity=100, limit_price=5.0) openapi_client.place_order(order) order_id = order.order_id # you can operate order via id too new_order = openapi_client.get_order(order_id=order.order_id) assert order.order_id == new_order.order_id openapi_client.modify_order(new_order, quantity=150) new_order = openapi_client.get_order(order_id=order_id) assert new_order.quantity == 150 openapi_client.cancel_order(order_id=order_id) new_order = openapi_client.get_order(order_id=order_id) assert new_order.status == OrderStatus.CANCELLED or new_order.status == OrderStatus.PENDING_CANCEL # 预览订单 (下单前后保证金要求, 佣金等预览) result = openapi_client.preview_order(order) print(result)
class TigerGateway(BaseGateway): """""" default_setting = { "tiger_id": "", "account": "", "standard_account": "", "private_key": '', } def __init__(self, event_engine): """Constructor""" super(TigerGateway, self).__init__(event_engine, "TIGER") self.tiger_id = "" self.account = "" self.standard_account = "" self.paper_account = "" self.language = "" self.client_config = None self.quote_client = None self.push_client = None self.local_id = 1000000 self.tradeid = 0 self.active = False self.queue = Queue() self.pool = None self.ID_TIGER2VT = {} self.ID_VT2TIGER = {} self.ticks = {} self.trades = set() self.contracts = {} self.symbol_names = {} def run(self): """""" while self.active: try: func, args = self.queue.get(timeout=0.1) func(*args) except Empty: pass def add_task(self, func, *args): """""" self.queue.put((func, [*args])) def connect(self, setting: dict): """""" self.private_key = setting['private_key'] self.tiger_id = setting["tiger_id"] self.account = setting["account"] self.standard_account = setting["standard_account"] self.paper_account = setting["account"] self.languege = Language.zh_CN # Start thread pool for REST call self.active = True self.pool = Pool(5) self.pool.apply_async(self.run) # Put connect task into quque. self.init_client_config() self.add_task(self.connect_quote) self.add_task(self.connect_trade) self.add_task(self.connect_push) def init_client_config(self, sandbox=True): """""" self.client_config = TigerOpenClientConfig(sandbox_debug=sandbox) self.client_config.private_key = self.private_key self.client_config.tiger_id = self.tiger_id self.client_config.account = self.account self.client_config.standard_account = self.standard_account self.client_config.paper_account = self.paper_account self.client_config.language = self.language def connect_quote(self): """ Connect to market data server. """ try: self.quote_client = QuoteClient(self.client_config) self.symbol_names = dict( self.quote_client.get_symbol_names(lang=Language.zh_CN)) self.query_contract() except ApiException: self.write_log("查询合约失败") return self.write_log("行情接口连接成功") self.write_log("合约查询成功") def connect_trade(self): """ Connect to trade server. """ self.trade_client = TradeClient(self.client_config) try: self.add_task(self.query_order) self.add_task(self.query_position) self.add_task(self.query_account) except ApiException: self.write_log("交易接口连接失败") return self.write_log("交易接口连接成功") def connect_push(self): """ Connect to push server. """ protocol, host, port = self.client_config.socket_host_port self.push_client = PushClient(host, port, (protocol == 'ssl')) self.push_client.connect( self.client_config.tiger_id, self.client_config.private_key) self.push_client.quote_changed = self.on_quote_change self.push_client.asset_changed = self.on_asset_change self.push_client.position_changed = self.on_position_change self.push_client.order_changed = self.on_order_change self.write_log("推送接口连接成功") def subscribe(self, req: SubscribeRequest): """""" self.push_client.subscribe_quote([req.symbol]) self.push_client.subscribe_asset() self.push_client.subscribe_position() self.push_client.subscribe_order() def on_quote_change(self, tiger_symbol: str, data: list, trading: bool): """""" data = dict(data) symbol, exchange = convert_symbol_tiger2vt(tiger_symbol) tick = self.ticks.get(symbol, None) if not tick: tick = TickData( symbol=symbol, exchange=exchange, gateway_name=self.gateway_name, datetime=datetime.now(), name=self.symbol_names[symbol], ) self.ticks[symbol] = tick tick.datetime = datetime.fromtimestamp(data["latest_time"] / 1000) tick.pre_close = data.get("prev_close", 0) tick.last_price = data.get("latest_price", 0) tick.volume = data.get("volume", 0) tick.open_price = data.get("open", 0) tick.open_price = data.get("open", 0) tick.high_price = data.get("high", 0) tick.low_price = data.get("low", 0) tick.ask_price_1 = data.get("ask_price", 0) tick.bid_price_1 = data.get("bid_price", 0) tick.ask_volume_1 = data.get("ask_size", 0) tick.bid_volume_1 = data.get("bid_size", 0) self.on_tick(copy(tick)) def on_asset_change(self, tiger_account: str, data: list): """""" data = dict(data) if "net_liquidation" not in data: return account = AccountData( accountid=tiger_account, balance=data["net_liquidation"], frozen=0.0, gateway_name=self.gateway_name, ) self.on_account(account) def on_position_change(self, tiger_account: str, data: list): """""" data = dict(data) symbol, exchange = convert_symbol_tiger2vt(data["origin_symbol"]) pos = PositionData( symbol=symbol, exchange=exchange, direction=Direction.NET, volume=int(data["quantity"]), frozen=0.0, price=data["average_cost"], pnl=data["unrealized_pnl"], gateway_name=self.gateway_name, ) self.on_position(pos) def on_order_change(self, tiger_account: str, data: list): """""" data = dict(data) print("委托推送", data["origin_symbol"], data["order_id"], data["filled"], data["status"]) symbol, exchange = convert_symbol_tiger2vt(data["origin_symbol"]) status = PUSH_STATUS_TIGER2VT[data["status"]] order = OrderData( symbol=symbol, exchange=exchange, orderid=self.ID_TIGER2VT.get( str(data["order_id"]), self.get_new_local_id()), direction=Direction.NET, price=data.get("limit_price", 0), volume=data["quantity"], traded=data["filled"], status=status, time=datetime.fromtimestamp( data["order_time"] / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_order(order) if status == Status.ALLTRADED: self.tradeid += 1 trade = TradeData( symbol=symbol, exchange=exchange, direction=Direction.NET, tradeid=self.tradeid, orderid=self.ID_TIGER2VT[str(data["order_id"])], price=data["avg_fill_price"], volume=data["filled"], time=datetime.fromtimestamp( data["trade_time"] / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_trade(trade) def get_new_local_id(self): self.local_id += 1 return self.local_id def send_order(self, req: OrderRequest): """""" local_id = self.get_new_local_id() order = req.create_order_data(local_id, self.gateway_name) self.on_order(order) self.add_task(self._send_order, req, local_id) return order.vt_orderid def _send_order(self, req: OrderRequest, local_id): """""" currency = config_symbol_currency(req.symbol) try: contract = self.trade_client.get_contracts( symbol=req.symbol, currency=currency)[0] order = self.trade_client.create_order( account=self.account, contract=contract, action=DIRECTION_VT2TIGER[req.direction], order_type=ORDERTYPE_VT2TIGER[req.type], quantity=int(req.volume), limit_price=req.price, ) self.ID_TIGER2VT[str(order.order_id)] = local_id self.ID_VT2TIGER[local_id] = str(order.order_id) self.trade_client.place_order(order) print("发单:", order.contract.symbol, order.order_id, order.quantity, order.status) except: # noqa traceback.print_exc() self.write_log("发单失败") return def cancel_order(self, req: CancelRequest): """""" self.add_task(self._cancel_order, req) def _cancel_order(self, req: CancelRequest): """""" try: order_id = self.ID_VT2TIGER[req.orderid] data = self.trade_client.cancel_order(order_id=order_id) except ApiException: self.write_log(f"撤单失败:{req.orderid}") if not data: self.write_log('撤单成功') def query_contract(self): """""" # HK Stock symbols_names_HK = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.HK) contract_names_HK = DataFrame( symbols_names_HK, columns=['symbol', 'name']) contractList = list(contract_names_HK["symbol"]) i, n = 0, len(contractList) result = pd.DataFrame() while i < n: i += 500 c = contractList[i - 500:i] r = self.quote_client.get_trade_metas(c) result = result.append(r) contract_detail_HK = result.sort_values(by="symbol", ascending=True) contract_HK = pd.merge( contract_names_HK, contract_detail_HK, how='left', on='symbol') for ix, row in contract_HK.iterrows(): contract = ContractData( symbol=row["symbol"], exchange=Exchange.SEHK, name=row["name"], product=Product.EQUITY, size=1, pricetick=row["min_tick"], net_position=True, gateway_name=self.gateway_name, ) self.on_contract(contract) self.contracts[contract.vt_symbol] = contract # US Stock symbols_names_US = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.US) contract_US = DataFrame(symbols_names_US, columns=['symbol', 'name']) for ix, row in contract_US.iterrows(): contract = ContractData( symbol=row["symbol"], exchange=Exchange.SMART, name=row["name"], product=Product.EQUITY, size=1, pricetick=0.001, gateway_name=self.gateway_name, ) self.on_contract(contract) self.contracts[contract.vt_symbol] = contract # CN Stock symbols_names_CN = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.CN) contract_CN = DataFrame(symbols_names_CN, columns=['symbol', 'name']) for ix, row in contract_CN.iterrows(): symbol = row["symbol"] symbol, exchange = convert_symbol_tiger2vt(symbol) contract = ContractData( symbol=symbol, exchange=exchange, name=row["name"], product=Product.EQUITY, size=1, pricetick=0.001, gateway_name=self.gateway_name, ) self.on_contract(contract) self.contracts[contract.vt_symbol] = contract def query_account(self): """""" try: assets = self.trade_client.get_assets() except ApiException: self.write_log("查询资金失败") return for i in assets: account = AccountData( accountid=self.account, balance=i.summary.net_liquidation, frozen=0.0, gateway_name=self.gateway_name, ) self.on_account(account) def query_position(self): """""" try: position = self.trade_client.get_positions() except ApiException: self.write_log("查询持仓失败") return for i in position: symbol, exchange = convert_symbol_tiger2vt(i.contract.symbol) pos = PositionData( symbol=symbol, exchange=exchange, direction=Direction.NET, volume=int(i.quantity), frozen=0.0, price=i.average_cost, pnl=float(i.unrealized_pnl), gateway_name=self.gateway_name, ) self.on_position(pos) def query_order(self): """""" try: data = self.trade_client.get_orders() data = sorted(data, key=lambda x: x.order_time, reverse=False) except: # noqa traceback.print_exc() self.write_log("查询委托失败") return self.process_order(data) self.process_deal(data) def close(self): """""" self.active = False if self.push_client: self.push_client.disconnect() def process_order(self, data): """""" for i in data: symbol, exchange = convert_symbol_tiger2vt(str(i.contract)) local_id = self.get_new_local_id() order = OrderData( symbol=symbol, exchange=exchange, orderid=local_id, direction=Direction.NET, price=i.limit_price if i.limit_price else 0.0, volume=i.quantity, traded=i.filled, status=STATUS_TIGER2VT[i.status], time=datetime.fromtimestamp( i.order_time / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.ID_TIGER2VT[str(i.order_id)] = local_id self.on_order(order) self.ID_VT2TIGER = {v: k for k, v in self.ID_TIGER2VT.items()} print("原始委托字典", self.ID_TIGER2VT) print("原始反向字典", self.ID_VT2TIGER) def process_deal(self, data): """ Process trade data for both query and update. """ for i in data: if i.status == ORDER_STATUS.PARTIALLY_FILLED or i.status == ORDER_STATUS.FILLED: symbol, exchange = convert_symbol_tiger2vt(str(i.contract)) self.tradeid += 1 trade = TradeData( symbol=symbol, exchange=exchange, direction=Direction.NET, tradeid=self.tradeid, orderid=self.ID_TIGER2VT[str(i.order_id)], price=i.avg_fill_price, volume=i.filled, time=datetime.fromtimestamp( i.trade_time / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_trade(trade)
class TigerGateway(BaseGateway): """""" default_setting = { "tiger_id": "", "account": "", "服务器": ["标准", "环球", "仿真"], "private_key": "", } # 在 VNTRADER 中展示的交易所列表 exchanges = [ Exchange.SEHK, Exchange.SMART, Exchange.SSE, Exchange.SZSE, Exchange.CFE, Exchange.ECBOT, Exchange.CMECRYPTO, Exchange.CFE, Exchange.GLOBEX, Exchange.NYMEX, Exchange.SGX, Exchange.HKFE ] def __init__(self, event_engine): """Constructor""" super(TigerGateway, self).__init__(event_engine, "TIGER") self.tiger_id = "" self.account = "" self.server = "" self.language = "" self.client_config = None self.quote_client = None self.push_client = None self.local_id = 1000000 self.tradeid = 0 self.active = False self.queue = Queue() self.pool = None self.ID_TIGER2VT = {} self.ID_VT2TIGER = {} self.ticks = {} self.trades = set() self.contracts = {} self.symbol_names = {} # {symbol NQ1909: (exchange, trading_contract)} self.vt_tiger_symbol_map = {} self.push_connected = False self.subscribed_symbols = set() def run(self): """""" while self.active: try: func, args = self.queue.get(timeout=0.1) func(*args) except Empty: pass except Exception: self.write_log('方法%s调用失败,参数为%s' % (func.__name__, args)) def add_task(self, func, *args): """""" self.queue.put((func, [*args])) def connect(self, setting: dict): """""" self.private_key = setting["private_key"] self.tiger_id = setting["tiger_id"] self.server = setting["服务器"] self.account = setting["account"] self.languege = Language.zh_CN # Start thread pool for REST call self.active = True self.pool = Pool(5) self.pool.apply_async(self.run) # Put connect task into quque. self.init_client_config() self.add_task(self.connect_quote) self.add_task(self.connect_trade) self.add_task(self.connect_push) def init_client_config(self, sandbox=SANDBOX): """""" self.client_config = TigerOpenClientConfig(sandbox_debug=sandbox) self.client_config.private_key = self.private_key self.client_config.tiger_id = self.tiger_id self.client_config.account = self.account self.client_config.language = self.language def connect_quote(self): """ Connect to market data server. """ try: self.quote_client = QuoteClient(self.client_config) self.symbol_names = dict( self.quote_client.get_symbol_names(lang=Language.zh_CN)) self.query_contract() except ApiException: self.write_log("查询合约失败") return self.write_log("行情接口连接成功") def connect_trade(self): """ Connect to trade server. """ self.write_log('查询交易接口') self.trade_client = TradeClient(self.client_config) try: self.add_task(self.query_order) self.add_task(self.query_position) self.add_task(self.query_account) except ApiException: self.write_log("交易接口连接失败") return self.write_log("交易接口连接成功") def connect_push(self): """ Connect to push server. """ protocol, host, port = self.client_config.socket_host_port self.push_client = PushClient(host, port, (protocol == "ssl")) self.push_client.quote_changed = self.on_quote_change self.push_client.asset_changed = self.on_asset_change self.push_client.position_changed = self.on_position_change self.push_client.order_changed = self.on_order_change self.push_client.connect_callback = self.on_push_connected self.push_client.disconnect_callback = self.on_disconnected self.push_client.connect(self.client_config.tiger_id, self.client_config.private_key) def subscribe(self, req: SubscribeRequest): """""" self.subscribed_symbols.add(req.symbol) if self.push_connected: self.push_client.subscribe_quote(symbols=[req.symbol], quote_key_type=QuoteKeyType.ALL) def on_push_connected(self): """""" self.push_connected = True self.write_log("推送接口连接成功") self.push_client.subscribe_asset(account=self.account) self.push_client.subscribe_position(account=self.account) self.push_client.subscribe_order(account=self.account) self.push_client.subscribe_quote(list(self.subscribed_symbols)) def on_disconnected(self): self.write_log('推送接口断开链接') self.push_connected = False def on_quote_change(self, tiger_symbol: str, data: list, trading: bool): """""" data = dict(data) symbol, exchange = self.get_vt_symbol_exchange(tiger_symbol) # 如果只推送了时间戳,或只推送了timeline,不向策略中推送新的tick事件 if 'latest_price' not in data and 'bid_price' not in data: return tick = self.ticks.get(symbol, None) if not tick: tick = TickData( symbol=symbol, exchange=exchange, gateway_name=self.gateway_name, datetime=datetime.now(), name=symbol, ) self.ticks[symbol] = tick # 本地止损单的设计依赖于limit up 与limit down(张跌停价格)。目前API中没有提供。 # 所以这里用high low 来代替 limit up 与limit down tick.datetime = datetime.fromtimestamp(int(data["timestamp"]) / 1000) tick.volume = data.get("volume", tick.volume) tick.ask_volume_1 = data.get("ask_size", tick.ask_volume_1) tick.bid_volume_1 = data.get("bid_size", tick.bid_volume_1) tick.pre_close = data.get("prev_close", tick.pre_close) tick.last_price = data.get("latest_price", tick.last_price) tick.open_price = data.get("open", tick.open_price) tick.high_price = data.get("high", tick.high_price) tick.low_price = data.get("low", tick.low_price) tick.ask_price_1 = data.get("ask_price", tick.ask_price_1) tick.bid_price_1 = data.get("bid_price", tick.bid_price_1) tick.limit_down = tick.low_price tick.limit_up = tick.high_price self.on_tick(copy(tick)) def on_asset_change(self, tiger_account: str, data: list): """""" data = dict(data) if "net_liquidation" not in data: return segment = data.get('segment') # 环球账户, 只推送summary的信息,含股票期货 if segment == 'summary' or segment is None: account = tiger_account # 标准账户有『子账户』的概念, 分别推送股票与期货账户的信息 elif segment == 'S': account = 'Security' elif segment == 'C': account = 'Commodity' account = AccountData( accountid=account, balance=round(data["net_liquidation"], 2), frozen=0.0, gateway_name=self.gateway_name, ) self.on_account(account) def on_position_change(self, tiger_account: str, data: list): """""" if tiger_account != self.account: return data = dict(data) # 处理标准与环球账户的差异, 环球的账户的期货信息要从originsymbol中获取,标准的从symbol中获取 origin_symbol = data.get("origin_symbol") if origin_symbol: symbol = origin_symbol2symbol(origin_symbol) else: symbol = data.get('symbol') symbol, exchange = self.get_vt_symbol_exchange(symbol) pos = PositionData( symbol=symbol, exchange=exchange, direction=Direction.NET, volume=int(data["quantity"]), frozen=0.0, price=round(data["average_cost"], 2), pnl=round(data["unrealized_pnl"], 2), gateway_name=self.gateway_name, ) self.on_position(pos) def on_order_change(self, tiger_account: str, data: list): """""" # 处理订阅了多个账户的情况 if tiger_account != self.account: return data = dict(data) origin_symbol = data.get("origin_symbol") if origin_symbol: symbol = origin_symbol2symbol(origin_symbol) else: symbol = data.get('symbol') symbol, exchange = self.get_vt_symbol_exchange(symbol) status = STATUS_TIGER2VT[data["status"]] order_time = data.get('order_time') order = OrderData( symbol=symbol, exchange=exchange, orderid=self.ID_TIGER2VT.get(str(data["id"]), self.get_new_local_id()), direction=DIRECTION_TIGER2VT[data.get('action')], price=data.get("limit_price", 0), volume=data["quantity"], traded=data["filled"], status=status, time=datetime.fromtimestamp(order_time / 1000).strftime("%H:%M:%S") if order_time else datetime.now().strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.ID_TIGER2VT[str(data["id"])] = order.orderid self.on_order(order) if status == Status.ALLTRADED: self.tradeid += 1 trade = TradeData( symbol=symbol, exchange=exchange, direction=DIRECTION_TIGER2VT[data.get('action')], tradeid=self.tradeid, orderid=self.ID_TIGER2VT[str(data["id"])], price=data["avg_fill_price"], volume=data["filled"], time=datetime.fromtimestamp(order_time / 1000).strftime("%H:%M:%S") if order_time else datetime.now().strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_trade(trade) def get_new_local_id(self): self.local_id += 1 return self.local_id def send_order(self, req: OrderRequest): """""" local_id = self.get_new_local_id() order = req.create_order_data(local_id, self.gateway_name) self.on_order(order) self.add_task(self._send_order, req, local_id) return order.vt_orderid def _send_order(self, req: OrderRequest, local_id): """""" try: # 主要处理一些API层面的校验带来的异常,如下单价格错误。 contract = self.get_trading_contract(req.symbol) order = self.trade_client.create_order( account=self.account, contract=contract, action=DIRECTION_VT2TIGER[req.direction], order_type=ORDERTYPE_VT2TIGER[req.type], quantity=int(req.volume), limit_price=round(req.price, 2), ) self.trade_client.place_order(order) self.ID_TIGER2VT[str(order.id)] = local_id self.ID_VT2TIGER[local_id] = str(order.id) except Exception: # 一些订单会在API层面被拒掉,不会推送订单的回报,这里模拟一个订单回报。 # 目前gateway 只实现了mkt 和limit 两种类型的订单,使用其他类型的订单也会出现异常。 # 这时本地的订单已经存在了, 所以返回一个状态为rejected的虚拟订单 symbol = contract2symbol(order.contract) symbol, exchange = self.get_vt_symbol_exchange(symbol) mock_order = OrderData( symbol=symbol, exchange=exchange, orderid=local_id, direction=DIRECTION_TIGER2VT[order.action], price=order.limit_price, volume=order.quantity, traded=0, status=Status.REJECTED, time=datetime.now().strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_order(mock_order) self.write_log("发单失败") traceback.print_exc() def cancel_order(self, req: CancelRequest): """""" self.add_task(self._cancel_order, req) def _cancel_order(self, req: CancelRequest): """""" try: id = self.ID_VT2TIGER[req.orderid] data = self.trade_client.cancel_order(id=id) if not data: self.write_log("撤单成功") except ApiException: self.write_log(f"撤单请求提交失败:{req.orderid}") traceback.print_exc() except Exception: self.write_log('撤单失败,id:%s' % (req.orderid)) def query_contract(self): """""" self.write_log('开始查询合约信息') # HK Stock # 查询的速度太慢了, 注释掉了 try: symbols_names_HK = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.HK) contract_names_HK = DataFrame(symbols_names_HK, columns=["symbol", "name"]) contractList = list(contract_names_HK["symbol"]) i, n = 0, len(contractList) result = DataFrame() while i < n: i += 50 c = contractList[i - 50:i] r = self.quote_client.get_trade_metas(c) result = result.append(r) sleep(0.1) except: self.write_log('查询港股合约失败') contract_detail_HK = result.sort_values(by="symbol", ascending=True) contract_HK = merge(contract_names_HK, contract_detail_HK, how="left", on="symbol") for ix, row in contract_HK.iterrows(): contract = ContractData( symbol=row["symbol"], exchange=Exchange.SEHK, name=row["name"], product=Product.EQUITY, size=1, min_volume=row["lot_size"], pricetick=row["min_tick"], net_position=True, gateway_name=self.gateway_name, ) self.on_contract(contract) self.contracts[contract.vt_symbol] = contract self.vt_tiger_symbol_map.update({ contract.symbol: (Exchange.SEHK, stock_contract(contract.symbol, currency='HKD')) }) # US Stock symbols_names_US = self.quote_client.get_symbol_names( lang=Language.zh_CN, market=Market.US) contract_US = DataFrame(symbols_names_US, columns=["symbol", "name"]) for ix, row in contract_US.iterrows(): contract = ContractData( symbol=row["symbol"], exchange=Exchange.SMART, name=row["name"], product=Product.EQUITY, size=1, min_volume=1, pricetick=0.001, gateway_name=self.gateway_name, ) self.on_contract(contract) self.vt_tiger_symbol_map.update({ contract.symbol: (Exchange.SMART, stock_contract(contract.symbol, currency='USD')) }) self.contracts[contract.vt_symbol] = contract self.write_log('初始化美股合约完成') # Future contracts exchanges = self.quote_client.get_future_exchanges( sec_type=SecurityType.FUT, lang=Language.zh_CN) exchanges_list = exchanges['code'] contract_futures = DataFrame() for e in exchanges_list: exchange_contract = self.quote_client.get_future_contracts( e, lang=Language.zh_CN) if len(exchange_contract) != 0: contract_futures = contract_futures.append(exchange_contract) for ix, row in contract_futures.iterrows(): contract = ContractData( # symbol 用于查询存储数据 NQ1909 symbol=row.loc['contract_code'], exchange=config_future_exchange(row.loc['exchange']), name=row.loc['name'], product=Product.FUTURES, size=1, min_volume=1, pricetick=0.001, gateway_name=self.gateway_name) self.on_contract(contract) self.vt_tiger_symbol_map.update({ contract.symbol: (contract.exchange, future_contract( symbol=row.type, currency=row.currency, expiry=row.last_trading_date, exchange=row.exchange, multiplier=row.multiplier, )) }) self.contracts[contract.vt_symbol] = contract self.write_log('初始化期货合约完成') def query_account(self): self.write_log('开始查询账户信息') try: assets = self.trade_client.get_assets(segment=True) except ApiException: self.write_log("查询资金失败") return for i in assets: account = AccountData( accountid=self.account, balance=round(i.summary.net_liquidation, 2), frozen=0.0, gateway_name=self.gateway_name, ) # 下面两个账户仅作vntrader 展示使用。 # 环球账户的资产信息可以通过 summary 获取,标准账户需要区分股票和期货Segment, 且没有合并的summary信息。 sec_account = AccountData( accountid='Security', balance=round(i.segments.get('S').net_liquidation, 2), frozen=0.0, gateway_name=self.gateway_name, ) com_account = AccountData( accountid='Commodity', balance=round(i.segments.get('C').net_liquidation, 2), frozen=0.0, gateway_name=self.gateway_name, ) self.on_account(account) self.on_account(sec_account) self.on_account(com_account) self.write_log('账户信息查询完成') def query_position(self): """""" self.write_log('开始查询持仓信息') try: # 分别查询股票和期货的持仓 stock_position = self.trade_client.get_positions( sec_type=SecurityType.STK) future_position = self.trade_client.get_positions( sec_type=SecurityType.FUT) positions = stock_position + future_position except ApiException: self.write_log("查询持仓失败") return for i in positions: try: # 标准账户里面的symbol 是origin symbol symbol, exchange = self.get_vt_symbol_exchange( contract2symbol(i.contract)) pos = PositionData( symbol=symbol, exchange=exchange, direction=Direction.NET, volume=int(i.quantity), frozen=0.0, price=i.average_cost, pnl=float(i.unrealized_pnl), gateway_name=self.gateway_name, ) self.on_position(pos) except: self.write_log('处理持仓失败,symbol: %s' % (i.contract.symbol)) self.write_log('持仓信息查询完成') def query_order(self): self.write_log('开始查询历史订单信息') try: # 需要分别查询股票和期货的订单 stock_data = self.trade_client.get_orders( account=self.account, sec_type=SecurityType.STK) future_data = self.trade_client.get_orders( account=self.account, sec_type=SecurityType.FUT) data = stock_data + future_data data = sorted(data, key=lambda x: x.order_time, reverse=False) except: traceback.print_exc() self.write_log("查询订单失败") return self.process_order(data) self.process_deal(data) self.write_log('历史订单处理完成') def close(self): """""" self.active = False if self.push_client: # 退出前先进行退订操作,避免下次打开时的订阅异常 try: self.push_client.unsubscribe_asset() self.push_client.unsubscribe_position() self.push_client.unsubscribe_order() self.push_client.unsubscribe_quote( symbols=self.subscribed_symbols) self.push_client.disconnect() except: pass def process_order(self, data): """""" for i in data: try: symbol = contract2symbol(i.contract) symbol, exchange = self.get_vt_symbol_exchange(symbol) local_id = self.get_new_local_id() order = OrderData( symbol=symbol, exchange=exchange, orderid=local_id, direction=DIRECTION_TIGER2VT[i.action], price=i.limit_price if i.limit_price else 0.0, volume=i.quantity, traded=i.filled, status=STATUS_TIGER2VT[i.status], time=datetime.fromtimestamp(i.order_time / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.ID_TIGER2VT[str(i.id)] = local_id self.on_order(order) except: pass self.ID_VT2TIGER = {v: k for k, v in self.ID_TIGER2VT.items()} def process_deal(self, data): """ Process trade data for both query and update. """ for i in data: if i.status == OrderStatus.PARTIALLY_FILLED or i.status == OrderStatus.FILLED: try: symbol = contract2symbol(i.contract) symbol, exchange = self.get_vt_symbol_exchange(symbol) self.tradeid += 1 trade = TradeData( symbol=symbol, exchange=exchange, direction=DIRECTION_TIGER2VT[i.action], tradeid=self.tradeid, orderid=self.ID_TIGER2VT[str(i.id)], price=i.avg_fill_price, volume=i.filled, time=datetime.fromtimestamp(i.trade_time / 1000).strftime("%H:%M:%S"), gateway_name=self.gateway_name, ) self.on_trade(trade) except: pass def get_vt_symbol_exchange(self, symbol): try: exchange = self.vt_tiger_symbol_map.get(symbol)[0] except: self.write_log('can not get symbol %s' % (symbol)) return symbol, exchange def get_trading_contract(self, symbol): """用于下单时获取交易合约 :param symbol: :return: """ try: return self.vt_tiger_symbol_map.get(symbol)[1] except: self.write_log('cannot get traidng contract for symbol %s' % (symbol))