import asyncio RESET_RATIO = 0 class MM: def __init__(self, logger, pair, lot, epsilon): self._logger = logger self._pair = pair self._lot = lot self._remain = 0 self._epsilon = epsilon self._buy_price = None self._sell_price = None self._buy = None self._sell = None self._buy_amount_sum = 0 self._sell_amount_sum = 0 self._income_sum = 0 self._outgo_sum = 0 self._total = 0 asyncio.create_task(self._main()) async def _main(self): self._logger.info("started") while True: pair = self._pair depth = pair.depth await depth.wait() if len(depth.bids) == 0 or len(depth.asks) == 0: continue ask = depth.asks[0][0] bid = depth.bids[0][0] enough_spread = (ask-bid) > self._epsilon*2 # calculate buy/sell thresh buy_max = 1e100 sell_min = 0 if self._sell_amount_sum > 0: buy_max = self._income_sum / self._sell_amount_sum if self._buy_amount_sum > 0: sell_min = self._outgo_sum / self._buy_amount_sum loss_cut = \ (buy_max - bid)/bid > 0.1 or \ (ask - sell_min)/ask > 0.1 # reset thresh if stock is consumed or to do cut loss if self._remain < self._lot or loss_cut: self._sell_amount_sum = 0 self._income_sum = 0 self._buy_amount_sum = 0 self._outgo_sum = 0 if self._sell is not None: # check current SELL order await asyncio.sleep(0.5) await self._sell.update() # get highest ask if ask == self._sell_price and depth.asks[0][1] > self._sell.remain: ask = depth.asks[1][0] if self._sell.done: amount = self._sell.amount - self._sell.remain if amount > 0: income = amount*self._sell.price self._sell_amount_sum += amount self._income_sum += income self._total += income self._logger.info(f" {amount} / {income} ({self._total})") self._remain -= self._sell.amount - self._sell.remain self._sell = None elif self._sell_price != max(sell_min, ask-self._epsilon): try: await self._sell.cancel() except Exception: pass elif enough_spread: # order SELL self._sell_price = max(sell_min, ask-self._epsilon) amount = self._lot if self._remain > self._lot*2: amount = self._remain - self._lot elif self._remain < self._lot: amount = 0 if amount > 0: self._sell = await self._order_sell(amount) if self._buy is not None: # check current BUY order await asyncio.sleep(0.5) await self._buy.update() # get lowest bid if bid == self._buy_price and depth.bids[0][1] > self._buy.remain: bid = depth.bids[1][0] if self._buy.done: amount = self._buy.amount - self._buy.remain if amount > 0: outgo = amount*self._buy.price self._buy_amount_sum += amount self._outgo_sum += outgo self._total -= outgo self._logger.info(f" {amount} / {outgo} ({self._total})") self._remain += self._buy.amount - self._buy.remain self._buy = None elif self._buy_price != min(buy_max, bid+self._epsilon): try: await self._buy.cancel() except Exception: pass elif enough_spread: # order BUY self._buy_price = min(buy_max, bid+self._epsilon) amount = self._lot if self._remain > self._lot*2: amount = 0 if amount > 0: self._buy = await self._order_buy(amount) async def _order_sell(self, amount): return await self._pair.sell_limit(amount, self._sell_price, True) async def _order_buy(self, amount): return await self._pair.buy_limit(amount, self._buy_price, True)