def login(self): self.pre_login() login_params = { 'username': '', 'areacode': '86', 'telephone': self._account, 'remember_me': '0', 'password': self._password } # 提交登录信息 r = self._session.post(url='https://xueqiu.com/user/login', data=login_params) r.raise_for_status() login_info = r.json() # 错误检查,并处理 if 'error_description' in login_info.keys(): self._expire_at = 0 logger.warning('Login Error: %s' % login_info['error_description']) raise TraderAPIError('Login Error: %s' % login_info['error_description']) # 登录成功 logger.info('Login Success. uid: %s, expire_at: %s' % (login_info['uid'], login_info['expires_in'])) return
def order_target_percent(self, symbol, target_percent, wait=10): ''' 根据持仓目标下单:按照最终持仓比例 :return: order_no, left ''' logger.info('order target percent: symbol: %s, target_percent: %s' % (symbol, target_percent)) if target_percent < 0: raise AttributeError('target_percent(%s) must be larger than 0.' % target_percent) if target_percent > 1: raise AttributeError('target_percent(%s) must be smaller than 1.' % target_percent) portfolio = self.portfolio portfolio_value = portfolio['market_value'].sum() target_volume = portfolio_value * target_percent base_volume = 0 if symbol in portfolio.index: base_volume = portfolio.loc[symbol, 'market_value'] volume = target_volume - base_volume if volume != 0: return self.order(symbol, volume=volume, wait=wait) else: return 0, 0
def exchange_stock_account(self): if self._exchange_stock_account is None: ex_account = self._trade_api(service_type='stock', function_id='407') self._exchange_stock_account = dict( ex_account[['exchange_type', 'stock_account']].values) logger.info('exchange_stock_account is: %s' % self.exchange_stock_account) return self._exchange_stock_account
def order(self, symbol, amount=0, volume=0, weight=0, portfolio=None): symbol = symbol.lower() logger.info( 'order: symbol(%s), amount(%.2f), volume(%.2f), weight(%.4f)' % (symbol, amount, volume, weight)) if amount == 0 and volume == 0 and weight == 0: return 0 if portfolio is None: portfolio = self.portfolio if amount != 0: if symbol in portfolio.index: volume = portfolio.loc[symbol, 'lasttrade'] * amount target_volume = portfolio.loc[symbol, 'market_value'] + volume target_weight = target_volume / portfolio['market_value'].sum() weight = target_weight - portfolio.loc[symbol, 'weight'] else: lasttrade = self.hq(symbol).loc[symbol, 'lasttrade'] target_volume = amount * lasttrade target_weight = target_volume / portfolio['market_value'].sum() weight = target_weight elif volume != 0: if symbol in portfolio.index: target_volume = portfolio.loc[symbol, 'market_value'] + volume target_weight = target_volume / portfolio['market_value'].sum() weight = target_weight - portfolio.loc[symbol, 'weight'] else: target_volume = volume target_weight = target_volume / portfolio['market_value'].sum() weight = target_weight else: if symbol in portfolio.index: target_weight = portfolio.loc[symbol, 'weight'] + weight else: target_weight = weight if target_weight > 1 or target_weight < 0: raise AttributeError( 'order: symbol(%s), amount(%.2f), volume(%.2f), weight(%.4f)' % (symbol, amount, volume, weight)) if weight > 0.001 or weight < -0.001: logger.debug('target_weight: %s' % round(target_weight, 4)) self._trade_api(symbol=symbol, target_percent=round(target_weight, 4), portfolio=portfolio) else: logger.info('权重变化过小,无需下单: %s' % weight) return 0
def keepalive(self, now=0): ''' 自动保持连接的函数 ''' if now == 0: now = time.time() logger.debug('keepalive checking. now: %s, expire_at: %s' % (now, self.expire_at)) if now + 60 > self.expire_at: self.portfolio logger.info('Reflash the expire time, expire_at timestamp is: %s' % self.expire_at) return
def order_target_volume(self, symbol, target_volume, wait=10): ''' 根据持仓目标下单:按照最终持仓金额 :return: order_no, left ''' logger.info('order target volume: symbol: %s, target_volume: %s' % (symbol, target_volume)) if target_volume < 0: raise AttributeError('target_volume(%s) must be larger than 0.' % target_volume) portfolio = self.portfolio base_volume = 0 if symbol in portfolio.index: base_volume = portfolio.loc[symbol, 'market_value'] volume = target_volume - base_volume if volume != 0: return self.order(symbol, volume=volume, wait=wait) else: return 0, 0
def order_target_amount(self, symbol, target_amount, wait=10): ''' 根据持仓目标下单:按最终持有数量 :return: order_no, left ''' logger.info('order target amount: symbol: %s, target_amount: %s' % (symbol, target_amount)) if target_amount < 0: raise AttributeError('target_amount(%s) must be larger than 0.' % target_amount) portfolio = self.portfolio base_amount = 0 if symbol in portfolio.index: base_amount = portfolio.loc[symbol, 'current_amount'] amount = target_amount - base_amount if amount != 0: return self.order(symbol, amount=amount, wait=wait) else: return 0, 0
def login(self): # 无论是否登录,都重新创建一个session对象 # self.pre_login() login_params = { "authtype": 2, "disknum": self.disknum, "loginType": 2, "origin": "web", 'mac': self.mac_address, 'username': self._account, 'password': self._password, 'tmp_yzm': self.vcode } resq = self._session.post(url='https://trade.gf.com.cn/login', params=login_params) resq.raise_for_status() logger.debug('login resq: %s' % resq.json()) data = resq.json() if data['success'] == True: v = resq.headers self._dse_sessionId = v['Set-Cookie'][-32:] # 等待服务器准备就绪 time.sleep(0.1) logger.info('Login success: %s' % self._dse_sessionId) return elif data['success'] == False and 'error_info' not in data.keys(): logger.warning('当前系统无法登陆') raise TraderAPIError(data) elif data['error_info'].find('验证码') != -1: self.dse_sessionId = None logger.warning('VerifyCode Error: %s' % data) raise VerifyCodeError(data['error_info']) else: self.dse_sessionId = None logger.warning('API Login Error: %s' % data) raise TraderAPIError(data['error_info'])
def order(self, symbol, amount=0, volume=0, wait=10): ''' 按数量下单 :return: order_no, left ''' logger.debug( 'order_amount: symbol: %s, amount: %s, volume: %s, wait: %s' % (symbol, amount, volume, wait)) if (amount == 0 and volume == 0): raise AttributeError('order_amount amount and volume can not be 0') # 下单 try: hq = self.hq(symbol) logger.debug('hq: %s' % hq.loc[symbol]) price = hq.loc[symbol, 'lasttrade'] amount = amount if amount else round(volume, 2) // price // 100 * 100 if amount == 0: return 0, 0 if amount > 0 or volume > 0: price = hq.loc[symbol, 'ask'] order_no = self.buy(symbol, price, amount=amount) logger.info('buy order send,order_no: %s' % order_no) elif amount < 0 or volume < 0: price = hq.loc[symbol, 'bid'] order_no = self.sell(symbol, price, amount=-amount) logger.info('sell order send,order_no: %s' % order_no) except TraderError as err: logger.debug('Order Error: %s' % err) raise err # 每隔2秒检查一下成交状态. # 如果是已成交,则返回order_no, 0 # 如果是已报、部成, 则再等2秒钟。 # 如果是其他状态,就报警 time.sleep(5) for i in range(int((wait + 1) / 2)): logger.info('Check Order Status %s times.' % i) orderlist = self.orderlist if order_no in orderlist.index: status = orderlist.loc[order_no, 'order_status'] else: # 如果记录的订单号不在orderlist里面,则认为已经成交了。 status = '已成' if status in ('已成'): logger.info('Order Success. %s' % orderlist.loc[order_no]) return order_no, 0 elif status in ('已报', '部成', '正常'): logger.info('Order not Complete. %s' % orderlist.loc[order_no]) time.sleep(5) elif status in ('未报'): logger.info('Not Allow to Send Order. %s' % orderlist.loc[order_no]) self.cancel(order_no) return order_no, amount else: logger.error('Order Status Invaild. %s' % orderlist.loc[order_no]) raise TraderAPIError('Order Status Invaild. %s' % orderlist.loc[order_no]) # 等待了足够时间,仍未全部成交,则撤单 try: logger.warning('Cancel order: %s' % order_no) self.cancel(order_no) time.sleep(0.3) orderlist = self.orderlist status = orderlist.loc[order_no, 'order_status'] if status in ('已撤', '部撤'): orderlist['left'] = orderlist['order_amount'] - orderlist[ 'business_amount'] left = orderlist.loc[order_no, 'left'] if amount < 0: left = -left return order_no, left else: raise TraderAPIError('Order Status Invaild. %s' % orderlist.loc[order_no]) except TraderError as err: logger.warning(err) logger.warning('Order Status Invaild. %s' % orderlist.loc[order_no])