2022-07-15 10:17:55 +00:00
|
|
|
import asyncio
|
|
|
|
|
|
|
|
|
|
|
|
class MM:
|
2022-07-17 07:40:56 +00:00
|
|
|
def __init__(self, logger, pair, lot, spread_amount, spread_band):
|
2022-07-15 10:17:55 +00:00
|
|
|
self._logger = logger
|
|
|
|
self._pair = pair
|
|
|
|
self._lot = lot
|
|
|
|
self._remain = 0
|
|
|
|
|
|
|
|
self._buy_price = None
|
|
|
|
self._sell_price = None
|
|
|
|
self._buy = None
|
|
|
|
self._sell = None
|
|
|
|
|
2022-07-17 07:40:56 +00:00
|
|
|
self._spread_amount = spread_amount
|
|
|
|
self._spread_band = spread_band
|
|
|
|
|
2022-07-15 10:17:55 +00:00
|
|
|
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
|
|
|
|
|
|
|
|
# calculate best amount to buy/sell
|
|
|
|
pos = self._remain / self._lot - 2
|
|
|
|
buy_amount = _quad( pos) * self._lot
|
|
|
|
sell_amount = _quad(-pos) * self._lot
|
|
|
|
|
2022-07-17 07:40:56 +00:00
|
|
|
# calculate ideal spread
|
|
|
|
ask_delta_amount = self._spread_amount * (_quad( pos) + self._spread_band)
|
|
|
|
bid_delta_amount = self._spread_amount * (_quad(-pos) + self._spread_band)
|
|
|
|
|
|
|
|
# calculate best sell price
|
|
|
|
if self._sell is not None and self._sell.done:
|
|
|
|
ask_delta_amount += self._sell.amount
|
|
|
|
ask = 0
|
|
|
|
prev = -1e100
|
|
|
|
for i in range(len(depth.asks)):
|
|
|
|
if (depth.asks[i][0]-prev) > pair.price_unit*1.5:
|
|
|
|
ask = depth.asks[i][0] - pair.price_unit
|
|
|
|
my_order = \
|
|
|
|
self._sell is not None and \
|
|
|
|
not self._sell.done and \
|
|
|
|
abs(self._sell_price-depth.asks[i][0]) < pair.price_unit
|
|
|
|
if my_order:
|
|
|
|
ask_delta_amount -= depth.asks[i][1] - self._sell.amount
|
|
|
|
prev = -1e100
|
|
|
|
else:
|
|
|
|
ask_delta_amount -= depth.asks[i][1]
|
|
|
|
prev = depth.asks[i][0]
|
|
|
|
if ask_delta_amount < 0:
|
|
|
|
break
|
|
|
|
|
|
|
|
# calculate best buy price
|
|
|
|
if self._buy is not None and self._buy.done:
|
|
|
|
bid_delta_amount += self._buy.amount
|
|
|
|
bid = 0
|
|
|
|
prev = 1e100
|
|
|
|
for i in range(len(depth.bids)):
|
|
|
|
if (prev-depth.bids[i][0]) > pair.price_unit*1.5:
|
|
|
|
bid = depth.bids[i][0] + pair.price_unit
|
|
|
|
my_order = \
|
|
|
|
self._buy is not None and \
|
|
|
|
not self._buy.done and \
|
|
|
|
abs(self._buy_price-depth.bids[i][0]) < pair.price_unit
|
|
|
|
if my_order:
|
|
|
|
bid_delta_amount -= depth.bids[i][1] - self._buy.amount
|
|
|
|
prev = 1e100
|
|
|
|
else:
|
|
|
|
bid_delta_amount -= depth.bids[i][1]
|
|
|
|
prev = depth.bids[i][0]
|
|
|
|
if bid_delta_amount < 0:
|
|
|
|
break
|
|
|
|
|
2022-07-15 10:17:55 +00:00
|
|
|
if self._sell is not None:
|
|
|
|
# check current SELL order
|
|
|
|
await asyncio.sleep(0.5)
|
|
|
|
await self._sell.update()
|
|
|
|
|
|
|
|
if self._sell.done:
|
|
|
|
amount = self._sell.amount - self._sell.remain
|
2022-07-17 01:54:39 +00:00
|
|
|
self._remain -= amount
|
2022-07-15 10:17:55 +00:00
|
|
|
if amount > 0:
|
|
|
|
income = amount*self._sell.price
|
|
|
|
self._total += income
|
2022-07-17 01:54:39 +00:00
|
|
|
self._logger.info(f"<SELL> {amount} / {income} ({self._remain} / {self._total})")
|
2022-07-15 10:17:55 +00:00
|
|
|
self._sell = None
|
2022-07-17 07:40:56 +00:00
|
|
|
elif abs(self._sell_price-ask) >= pair.price_unit:
|
2022-07-17 01:54:39 +00:00
|
|
|
await self._sell.cancel()
|
2022-07-17 07:40:56 +00:00
|
|
|
elif sell_amount >= pair.order_unit:
|
2022-07-15 10:17:55 +00:00
|
|
|
# order SELL
|
2022-07-17 07:40:56 +00:00
|
|
|
self._sell_price = ask
|
2022-07-15 10:17:55 +00:00
|
|
|
self._sell = await self._order_sell(sell_amount)
|
|
|
|
|
|
|
|
if self._buy is not None:
|
|
|
|
# check current BUY order
|
|
|
|
await self._buy.update()
|
|
|
|
|
|
|
|
if self._buy.done:
|
|
|
|
amount = self._buy.amount - self._buy.remain
|
2022-07-17 01:54:39 +00:00
|
|
|
self._remain += amount
|
2022-07-15 10:17:55 +00:00
|
|
|
if amount > 0:
|
|
|
|
outgo = amount*self._buy.price
|
|
|
|
self._total -= outgo
|
2022-07-17 01:54:39 +00:00
|
|
|
self._logger.info(f"<BUY> {amount} / {outgo} ({self._remain} / {self._total})")
|
2022-07-15 10:17:55 +00:00
|
|
|
self._buy = None
|
2022-07-17 07:40:56 +00:00
|
|
|
elif abs(self._buy_price-bid) >= pair.price_unit:
|
2022-07-17 01:54:39 +00:00
|
|
|
await self._buy.cancel()
|
2022-07-17 07:40:56 +00:00
|
|
|
elif buy_amount >= pair.order_unit:
|
2022-07-15 10:17:55 +00:00
|
|
|
# order BUY
|
2022-07-17 07:40:56 +00:00
|
|
|
self._buy_price = bid
|
2022-07-15 10:17:55 +00:00
|
|
|
self._buy = await self._order_buy(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)
|
|
|
|
|
|
|
|
|
|
|
|
# https://kijitora-2018.hatenablog.com/entry/2018/12/23/102913
|
|
|
|
def _quad(x):
|
|
|
|
if x < -1:
|
|
|
|
return 1
|
|
|
|
if x <= 1:
|
|
|
|
return -1/4 * (x+1)**2 + 1
|
|
|
|
return 0
|