bybit_usdt_swap_rest.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. import imp
  2. import random
  3. import re
  4. import aiohttp
  5. import time
  6. import asyncio
  7. import zlib
  8. import json, ujson
  9. import hmac
  10. import base64
  11. import hashlib
  12. import traceback
  13. import urllib
  14. from urllib import parse
  15. from urllib.parse import urljoin
  16. import datetime, sys
  17. from urllib.parse import urlparse
  18. import logging, logging.handlers
  19. import utils
  20. import logging, logging.handlers
  21. import model
  22. from decimal import Decimal
  23. def empty_call(msg):
  24. print(f'空的回调函数 {msg}')
  25. def parse_params_to_str(params):
  26. url = ''
  27. for key in sorted(params.keys()):
  28. value = params[key]
  29. if isinstance(value, bool):
  30. if params[key]:
  31. value = "true"
  32. else:
  33. value = "false"
  34. url = url + str(key) + '=' + str(value) + '&'
  35. return url[0:-1]
  36. class BybitUsdtSwapRest:
  37. def __init__(self, params:model.ClientParams, colo=0):
  38. if colo:
  39. print('不支持colo高速线路')
  40. self.HOST = 'https://api.bybit.com'
  41. else:
  42. self.HOST = 'https://api.bybit.com'
  43. self.params = params
  44. self.name = self.params.name
  45. self.base = self.params.pair.split('_')[0].upper()
  46. self.quote = self.params.pair.split('_')[1].upper()
  47. self.symbol = self.base + self.quote
  48. self._SESSIONS = dict()
  49. self.logger = self.get_logger()
  50. self.callback = {
  51. "onMarket":empty_call,
  52. "onPosition":empty_call,
  53. "onOrder":empty_call,
  54. "onEquity":empty_call,
  55. "onTicker":empty_call,
  56. "onDepth":empty_call,
  57. "onExit":empty_call,
  58. }
  59. self.exchange_info = dict()
  60. self.tickSize = None
  61. self.stepSize = None
  62. self.delays = []
  63. self.max_delay = 0
  64. self.avg_delay = 0
  65. self.proxy = None
  66. if 'win' in sys.platform:
  67. self.proxy = self.params.proxy
  68. self.logger = self.get_logger()
  69. self.mp_from_rest = None
  70. self.stop_flag = 0
  71. self.coin_value = 0.0
  72. self.cash_value = 0.0
  73. self.min_trade_amount = 0.0
  74. self.rate_limit_left = 120
  75. #### 指定发包ip
  76. iplist = utils.get_local_ip_list()
  77. self.ip = iplist[int(self.params.ip)]
  78. def get_logger(self):
  79. logger = logging.getLogger(__name__)
  80. logger.setLevel(logging.DEBUG)
  81. # log to txt
  82. formatter = logging.Formatter('[%(asctime)s] - %(levelname)s - %( message)s')
  83. handler = logging.handlers.RotatingFileHandler(f"log.log",maxBytes=1024*1024)
  84. handler.setLevel(logging.DEBUG)
  85. handler.setFormatter(formatter)
  86. logger.addHandler(handler)
  87. return logger
  88. def get_logger(self):
  89. logger = logging.getLogger(__name__)
  90. logger.setLevel(logging.DEBUG)
  91. # log to txt
  92. formatter = logging.Formatter('[%(asctime)s] - %(levelname)s - %(message)s')
  93. handler = logging.handlers.RotatingFileHandler("log.log",maxBytes=1024*1024,encoding='utf-8')
  94. handler.setLevel(logging.DEBUG)
  95. handler.setFormatter(formatter)
  96. # log to console
  97. console = logging.StreamHandler()
  98. console.setLevel(logging.WARNING)
  99. logger.addHandler(handler)
  100. logger.addHandler(console)
  101. return logger
  102. def _get_session(self, url):
  103. parsed_url = urlparse(url)
  104. key = parsed_url.netloc or parsed_url.hostname
  105. if key not in self._SESSIONS:
  106. tcp = aiohttp.TCPConnector(limit=50,keepalive_timeout=120,verify_ssl=False,local_addr=(self.ip,0))
  107. session = aiohttp.ClientSession(connector=tcp)
  108. self._SESSIONS[key] = session
  109. return self._SESSIONS[key]
  110. def get_sign(self, params, secret_key):
  111. message = parse_params_to_str(params)
  112. # mac = hmac.new(bytes(secret_key, encoding='utf-8'), bytes(message, encoding='utf-8'), digestmod='sha256').digest()
  113. hash = hmac.new(bytes(secret_key, encoding='utf-8'), bytes(message, encoding='utf-8'), hashlib.sha256)
  114. signature = hash.hexdigest()
  115. return signature
  116. async def _request(self, method, uri, body=None, params=None, auth=False):
  117. url = urljoin(self.HOST, uri)
  118. headers = {}
  119. if auth:
  120. if method in ['GET']:
  121. timestamp = str(int(time.time()*1000))
  122. params['timestamp'] = timestamp
  123. params['api_key'] = self.params.access_key
  124. params['recv_window'] = "15000"
  125. params['sign'] = self.get_sign(params, self.params.secret_key)
  126. headers = {}
  127. elif method == 'POST':
  128. timestamp = str(int(time.time()*1000))
  129. params['timestamp'] = timestamp
  130. params['api_key'] = self.params.access_key
  131. params['recv_window'] = "15000"
  132. params['sign'] = self.get_sign(params, self.params.secret_key)
  133. headers = {}
  134. url = url + '?' + parse_params_to_str(params)
  135. # 发起请求
  136. session = self._get_session(url)
  137. timeout = aiohttp.ClientTimeout(10)
  138. msg = "rest请求记录" + str(method) + str(url) + str(params) + str(body)
  139. self.logger.debug(msg)
  140. try:
  141. start_time = time.time()
  142. if method == "GET":
  143. response = await session.get(url, params=params, headers=headers, timeout=timeout, proxy=self.proxy)
  144. elif method == "POST":
  145. response = await session.post(url, data=ujson.dumps(params), headers=headers, timeout=timeout, proxy=self.proxy)
  146. elif method == "DELETE":
  147. response = await session.delete(url, params=params, data=body, headers=headers, timeout=timeout, proxy=self.proxy)
  148. code = response.status
  149. res = await response.json(content_type=None)
  150. delay = int(1000*(time.time() - start_time))
  151. self.delays.append(delay)
  152. res_msg = msg + f' 回报 {res}'
  153. self.logger.debug(res_msg)
  154. #### 检查频率限制
  155. if 'rate_limit_status' in res:
  156. self.rate_limit_left = res['rate_limit_status']
  157. if self.rate_limit_left < 20:
  158. self.callback['onExit'](f"{self.name} 即将触发限频封禁 紧急退出")
  159. ####
  160. if code not in (200, 201, 202, 203, 204, 205, 206) or res['ret_code'] not in [0]:
  161. self.logger.error(f'URL:{url} PARAMS:{params} body:{body} ERROR:{res}')
  162. return None, str(res)
  163. return res, None
  164. except Exception as e:
  165. print(f'{self.name} rest 请求出错', str(e))
  166. self.logger.error(f'请求错误 {msg}'+str(e))
  167. self.logger.error(traceback.format_exc())
  168. return None, e
  169. async def get_position(self):
  170. response, error = await self._request('GET', '/private/linear/position/list', params={}, auth=1)
  171. if error:
  172. print(error)
  173. if response:
  174. position = model.Position()
  175. for j in response['result']:
  176. i = j['data']
  177. if i['symbol'] == self.symbol:
  178. side = i['side'].lower()
  179. pos = float(i['size'])
  180. price = float(i['entry_price'])
  181. if side == 'buy':
  182. position.longPos = pos
  183. position.longAvg = price
  184. elif side == 'sell':
  185. position.shortPos = pos
  186. position.shortAvg = price
  187. return position
  188. async def buy_token(self):
  189. '''买入平台币'''
  190. pass
  191. async def check_position(self, hold_coin=0.0):
  192. '''
  193. 现货交易 已支持全品种
  194. '''
  195. try:
  196. #######################
  197. self.logger.info("清空挂单")
  198. params = {
  199. 'symbol':self.symbol,
  200. }
  201. response, error = await self._request('POST', '/private/linear/order/cancel-all', params=params, auth=1)
  202. if error:
  203. self.logger.info("全部撤单失败")
  204. if response:
  205. self.logger.info("全部撤单成功")
  206. #############################
  207. self.logger.info("清空仓位")
  208. res, err = await self._request('GET', '/private/linear/position/list', params={}, auth=1)
  209. if err:
  210. self.logger.info(err)
  211. if res:
  212. for i in res['result']:
  213. if float(i['data']['size']) > 0:
  214. ####
  215. response ,error = await self._request('GET',f'/v2/public/orderBook/L2', params={"symbol":i['data']['symbol']}, auth=0)
  216. if response:
  217. bids = []
  218. asks = []
  219. for j in response['result']:
  220. if j['side'].lower() == 'buy':
  221. bids.append(float(j['price']))
  222. if j['side'].lower() == 'sell':
  223. asks.append(float(j['price']))
  224. ap = min(asks)
  225. bp = max(bids)
  226. mp = (ap+bp)*0.5
  227. if error:
  228. print(error)
  229. ####
  230. if self.exchange_info == dict():
  231. await self.before_trade()
  232. ####
  233. if i['data']['side'].lower() == 'buy':
  234. _side = "pd"
  235. _price = utils.fix_price(mp * 0.999, self.exchange_info[i['data']['symbol']].tickSize)
  236. elif i['data']['side'].lower() == 'sell':
  237. _side = "pk"
  238. _price = utils.fix_price(mp * 1.001, self.exchange_info[i['data']['symbol']].tickSize)
  239. ####
  240. response = await self.take_order(
  241. i['data']['symbol'],
  242. float(i['data']['size']),
  243. _side,
  244. _price,
  245. utils.get_cid()
  246. )
  247. if response:
  248. print(response)
  249. #######################
  250. except:
  251. self.logger.error("清仓程序执行出错")
  252. self.logger.error(traceback.format_exc())
  253. return
  254. async def take_order(self, symbol, amount, origin_side, price, cid="", order_type='limit'):
  255. '''
  256. 下单
  257. price: 限价时 为 必填
  258. marginCoin: 保证金币种
  259. size: 限价时 为 数量 市价买 为额度 卖为数量
  260. side: open_long open_short close_long close_short
  261. orderType: limit(限价) market(市价)
  262. timeInForceValue:normal(普通限价订单) postOnly(只做maker,市价不允许使用这个) ioc(立即成交并取消剩余) fok(全部成交或立即取消)
  263. presetTakeProfitPrice: 预设止盈价格
  264. presetStopLossPrice: 预设止损价格
  265. '''
  266. if origin_side =='kd':
  267. side = "Buy"
  268. reduce_only = "false"
  269. elif origin_side =='pd':
  270. side = "Sell"
  271. reduce_only = "true"
  272. elif origin_side =='kk':
  273. side = "Sell"
  274. reduce_only = "false"
  275. elif origin_side =='pk':
  276. side = "Buy"
  277. reduce_only = "true"
  278. else:
  279. print("合约不允许此交易方向")
  280. return None
  281. if self.rate_limit_left < 40 and origin_side in ['kd','kk']:
  282. print("即将触发限频 停止开仓单发单")
  283. order_event = dict()
  284. order_event['status'] = "REMOVE"
  285. order_event['filled_price'] = 0.0
  286. order_event['fee'] = 0.0
  287. order_event['filled'] = 0.0
  288. order_event['client_id'] = cid
  289. self.callback["onOrder"](order_event)
  290. return
  291. if symbol not in self.exchange_info:
  292. await self.before_trade()
  293. # amount = utils.fix_amount(amount, self.exchange_info[symbol].stepSize)
  294. # price = utils.fix_price(price, self.exchange_info[symbol].tickSize)
  295. # amount = float(Decimal(str(amount))//Decimal(str(self.exchange_info[symbol].stepSize))*Decimal(str(self.exchange_info[symbol].stepSize)))
  296. # price = float(int(Decimal(str(price))/Decimal(str(self.exchange_info[symbol].tickSize)))*Decimal(str(self.exchange_info[symbol].tickSize)))
  297. if float(price) <= 0.0:
  298. self.logger.error(f'下单参数错误 price:{price}')
  299. order_event = dict()
  300. order_event['status'] = "REMOVE"
  301. order_event['filled_price'] = 0.0
  302. order_event['fee'] = 0.0
  303. order_event['filled'] = 0.0
  304. order_event['client_id'] = cid
  305. self.callback["onOrder"](order_event)
  306. return None
  307. if float(amount) <=0:
  308. self.logger.error(f'下单参数错误 amount:{amount}')
  309. order_event = dict()
  310. order_event['status'] = "REMOVE"
  311. order_event['filled_price'] = 0.0
  312. order_event['fee'] = 0.0
  313. order_event['filled'] = 0.0
  314. order_event['client_id'] = cid
  315. self.callback["onOrder"](order_event)
  316. return None
  317. params = {
  318. "order_link_id":cid,
  319. "symbol": symbol,
  320. "qty":utils.num_to_str(amount, self.exchange_info[symbol].stepSize),
  321. "side": side,
  322. "reduce_only":reduce_only,
  323. "close_on_trigger":False,
  324. "time_in_force":"GoodTillCancel",
  325. }
  326. if order_type == 'limit':
  327. params["order_type"] = "Limit"
  328. params["price"] = utils.num_to_str(price, self.exchange_info[symbol].tickSize)
  329. elif order_type == 'market':
  330. params["order_type"] = "Market"
  331. if self.params.debug == 'True':
  332. return await asyncio.sleep(0.1)
  333. else:
  334. # 发单
  335. if order_type == 'limit':
  336. response, error = await self._request('POST', '/private/linear/order/create', params=params, auth=1)
  337. elif order_type == 'market':
  338. response, error = await self._request('POST', '/private/linear/order/create', params=params, auth=1)
  339. # 再更新
  340. if response:
  341. # 增加新的
  342. if 'result' in response:
  343. order_event = dict()
  344. order_event['status'] = "NEW"
  345. order_event['client_id'] = cid
  346. order_event['order_id'] = response['result']["order_id"]
  347. self.callback["onOrder"](order_event)
  348. if error:
  349. order_event = dict()
  350. order_event['status'] = "REMOVE"
  351. order_event['filled_price'] = 0.0
  352. order_event['fee'] = 0.0
  353. order_event['filled'] = 0.0
  354. order_event['client_id'] = cid
  355. self.callback["onOrder"](order_event)
  356. return response
  357. async def cancel_order(self, order_id=None, client_id=None):
  358. '''
  359. symbol String 是 产品ID 必须大写
  360. marginCoin String 是 保证金币种 必须大写
  361. orderId String 是 订单号
  362. '''
  363. if order_id:
  364. response, error = await self._request('POST', f'/private/linear/order/cancel', params={'symbol':self.symbol,'order_id':order_id}, auth=1)
  365. elif client_id:
  366. response, error = await self._request('POST', f'/private/linear/order/cancel', params={'symbol':self.symbol,'order_link_id':client_id}, auth=1)
  367. else:
  368. raise Exception("撤单出错 没指定订单号")
  369. if response:
  370. pass
  371. # await self.check_order(order_id=response['data']['orderId'])
  372. # self.logger.debug(f'撤单回报 {response}')
  373. # order_event = dict()
  374. # order_event['status'] = "REMOVE"
  375. # order_event['filled_price'] = float(response['data']['price'])
  376. # order_event['fee'] = float(response['data']["deal_fee"])
  377. # order_event['filled'] = float(response['data']['amount']) - float(response['data']['left'])
  378. # order_event['client_id'] = response['data']["client_id"]
  379. # self.callback["onOrder"](order_event)
  380. if error:
  381. pass
  382. # print("撤单失败",error)
  383. # self.logger.error(error)
  384. return response
  385. async def check_order(self, order_id=None, client_id=None):
  386. '''
  387. symbol String 是 产品ID 必须大写
  388. orderId String 是 订单号
  389. '''
  390. if order_id:
  391. response, error = await self._request('GET', f'/private/linear/order/search', params={'symbol':self.symbol, 'order_id':order_id}, auth=1)
  392. elif client_id:
  393. response, error = await self._request('GET', f'/private/linear/order/search', params={'symbol':self.symbol, 'order_link_id':client_id}, auth=1)
  394. else:
  395. return
  396. if response:
  397. self.logger.debug(f'查单回报 {response}')
  398. if response['result']:
  399. if response['result']["order_status"] == 'New': # 新增订单
  400. order_event = dict()
  401. order_event['status'] = "NEW"
  402. order_event['filled'] = 0
  403. order_event['filled_price'] = 0
  404. order_event['client_id'] = response['result']["order_link_id"] if "order_link_id" in response['result'] else ""
  405. order_event['order_id'] = response['result']['order_id']
  406. order_event['fee'] = 0.0
  407. self.callback["onOrder"](order_event)
  408. # print(order_event)
  409. elif response['result']["order_status"] in ['Filled','Cancelled']: # 删除订单
  410. # fee 负数是扣手续费 bitget没有返佣
  411. order_event = dict()
  412. order_event['status'] = "REMOVE"
  413. order_event['client_id'] = response['result']["order_link_id"] if "order_link_id" in response['result'] else ""
  414. order_event['order_id'] = response['result']['order_id']
  415. order_event['filled'] = float(response['result']["cum_exec_qty"])
  416. order_event['filled_price'] = float(response['result']["last_exec_price"]) \
  417. if 'last_exec_price' in response['result'] else float(response['result']['price'])
  418. order_event['fee'] = float(response['result']['cum_exec_fee'])
  419. self.callback["onOrder"](order_event)
  420. # print(order_event)
  421. if error:
  422. print("查单失败",error)
  423. self.logger.error(error)
  424. return response
  425. async def get_order_list(self):
  426. params = {
  427. 'market':self.symbol,
  428. 'offset':100,
  429. "side":0,
  430. 'limit':100,
  431. }
  432. response, error = await self._request('GET', '/perpetual/v1/order/pending', params=params, auth=1)
  433. if response is not None:
  434. for i in response['data']['records']:
  435. order_event = dict()
  436. order_event['symbol'] = self.symbol
  437. order_event['price'] = float(i["price"])
  438. order_event['amount'] = float(i["amount"])
  439. order_event['filled'] = float(i["amount"])-float(i["left"])
  440. order_event['filled_price'] = float(i["avg_price"])
  441. order_event['client_id'] = i["clientOid"]
  442. order_event['order_id'] = i['id']
  443. asset_fee = float(response['data']["asset_fee"])
  444. money_fee = float(response['data']["money_fee"])
  445. stock_fee = float(response['data']["stock_fee"])
  446. if asset_fee > 0.0: # 非amm品种
  447. order_event['fee'] = asset_fee
  448. else: # amm品种
  449. order_event['fee'] = money_fee if money_fee > 0.0 else stock_fee
  450. if response["data"]['status'] == 'not_deal':
  451. order_event['status'] = "NEW"
  452. elif response["data"]['status'] in ['cancel','done']:
  453. order_event['status'] = "REMOVE"
  454. else:
  455. s = response["data"]['status']
  456. self.logger.error(f"错误的订单状态 {s}")
  457. self.callback["onOrder"](order_event)
  458. if error:
  459. print(error)
  460. return response
  461. async def get_server_time(self):
  462. params = {}
  463. response = await self._request('GET', '/perpetual/api/v1/timestamp', params=params)
  464. return response
  465. async def get_account(self):
  466. '''
  467. symbol String 是 产品ID 必须大写
  468. marginCoin String 是 保证金币种
  469. '''
  470. return await self._request('GET','/v2/private/wallet/balance', params={}, auth=1)
  471. async def transfer(self):
  472. '''
  473. '''
  474. from uuid import uuid4
  475. params = {
  476. "transfer_id":str(uuid4()),
  477. "coin":"USDT",
  478. "amount":"200",
  479. "from_account_type":"SPOT",
  480. "to_account_type":"CONTRACT",
  481. }
  482. return await self._request('POST','/asset/v1/private/transfer', params=params, auth=1)
  483. async def get_all_sub_account(self):
  484. '''
  485. '''
  486. params = {
  487. }
  488. return await self._request('GET','/asset/v1/private/sub-member/member-ids', params=params, auth=1)
  489. async def get_market_details(self):
  490. return await self._request('GET',f'/v2/public/symbols', params={}, auth=0)
  491. async def get_ticker(self):
  492. ####
  493. response ,error = await self._request('GET',f'/v2/public/orderBook/L2', params={"symbol":self.symbol}, auth=0)
  494. if response:
  495. bids = []
  496. asks = []
  497. for j in response['result']:
  498. if j['side'].lower() == 'buy':
  499. bids.append(float(j['price']))
  500. if j['side'].lower() == 'sell':
  501. asks.append(float(j['price']))
  502. ap = min(asks)
  503. bp = max(bids)
  504. mp = (ap+bp)*0.5
  505. d = {"name":self.name,'mp': mp, 'bp':bp, 'ap':ap}
  506. self.callback['onTicker'](d)
  507. return d
  508. if error:
  509. self.logger.error(error)
  510. return None
  511. async def before_trade(self):
  512. # 切换杠杆
  513. await self.change_position_side()
  514. # 获取市场最新价格
  515. res = await self.get_ticker()
  516. ticker_price = res["mp"]
  517. if isinstance(ticker_price, float):
  518. self.mp_from_rest = ticker_price
  519. # 获取市场基本情况
  520. res, error = await self.get_market_details()
  521. if error:
  522. pass
  523. else:
  524. for i in res['result']:
  525. if i['name'] == self.symbol:
  526. self.stepSize = float(i['lot_size_filter']['qty_step'])
  527. self.tickSize = float(i['price_filter']['tick_size'])
  528. self.min_trade_amount = 0.0
  529. #### 保存交易规则信息
  530. exchange_info = model.ExchangeInfo()
  531. exchange_info.symbol = i['name']
  532. exchange_info.multiplier = 1
  533. exchange_info.stepSize = float(i['lot_size_filter']['qty_step'])
  534. exchange_info.tickSize = float(i['price_filter']['tick_size'])
  535. self.exchange_info[exchange_info.symbol] = exchange_info
  536. async def get_equity(self):
  537. # 更新账户
  538. res, err = await self.get_account()
  539. if err:print(err)
  540. if res:
  541. for i in res['result']:
  542. if self.quote == i:
  543. cash = float(res['result'][i]['equity'])
  544. self.callback['onEquity']({
  545. self.quote:cash
  546. })
  547. self.cash_value = cash
  548. async def change_position_side(self):
  549. '''切换到全仓'''
  550. res ,err = await self._request(
  551. 'POST',
  552. '/private/linear/position/switch-mode',
  553. params={
  554. 'symbol':self.symbol,
  555. 'mode':"BothSide",},
  556. auth=1
  557. )
  558. if err:print(err)
  559. if res:print(res)
  560. async def go(self):
  561. interval = 60 # 不能太快防止占用限频
  562. await self.before_trade()
  563. await asyncio.sleep(1)
  564. while 1:
  565. try:
  566. # 停机信号
  567. if self.stop_flag:return
  568. # 更新账户
  569. res, err = await self.get_account()
  570. if err:print(err)
  571. if res:
  572. for i in res['result']:
  573. if self.quote == i:
  574. cash = float(res['result'][i]['equity'])
  575. self.callback['onEquity']({
  576. self.quote:cash
  577. })
  578. self.cash_value = cash
  579. # 更新仓位
  580. p = await self.get_position()
  581. self.callback['onPosition'](p)
  582. await asyncio.sleep(interval)
  583. # 打印延迟
  584. self.get_delay_info()
  585. self.logger.debug(f'报单延迟 平均{self.avg_delay}ms 最大{self.max_delay}ms')
  586. except:
  587. traceback.print_exc()
  588. await asyncio.sleep(10)
  589. def get_delay_info(self):
  590. if len(self.delays) > 100:
  591. self.delays = self.delays[-100:]
  592. if max(self.delays) > self.max_delay:self.max_delay = max(self.delays)
  593. self.avg_delay = round(sum(self.delays)/len(self.delays),1)
  594. async def handle_signals(self, orders):
  595. '''执行策略指令'''
  596. try:
  597. for order_name in orders:
  598. if 'Cancel' in order_name:
  599. # cid = orders[order_name][0]
  600. oid = orders[order_name][1]
  601. # 只能用oid撤单
  602. if oid:
  603. asyncio.get_event_loop().create_task(self.cancel_order(order_id=oid))
  604. for order_name in orders:
  605. if 'Limits' in order_name:
  606. for i in orders[order_name]:
  607. asyncio.get_event_loop().create_task(self.take_order(
  608. self.symbol,
  609. i[0],
  610. i[1],
  611. i[2],
  612. i[3]
  613. ))
  614. for order_name in orders:
  615. if 'Check' in order_name:
  616. # cid = orders[order_name][0]
  617. oid = orders[order_name][1]
  618. # 只能用oid查单
  619. if oid:
  620. asyncio.get_event_loop().create_task(self.check_order(order_id=oid))
  621. except Exception as e:
  622. traceback.print_exc()
  623. self.logger.error("执行信号出错"+str(e))
  624. await asyncio.sleep(0.1)