async def cancel_order(self, client: aiohttp.ClientSession, order_id: int) -> (bool, float):
     """ Cancel a regular order, return success and executed quantity """
     params = {
         'symbol': self.pair['symbol'],
         'orderId': order_id
     }
     try:
         _, resp = await self.req(client, 'DELETE', 'order', params, {})
         CColors.iprint(f'Canceled limit order #{order_id} (status: {resp["status"]})')
         return True, float(resp['executedQty'])
     except BinanceAPI.ApiError as exc:
         CColors.eprint(f'Order cancel failed with {exc.data}')
         return False, 0
 async def cancel_oco_order(self, client: aiohttp.ClientSession,
                            order_list_id: int) -> (bool, float):
     """ Cancel an OCO order, return success and executed quantity """
     params = {
         'symbol': self.pair['symbol'],
         'orderListId': order_list_id
     }
     try:
         _, resp = await self.req(client, 'DELETE', 'orderList', params, {})
         CColors.iprint(f'Canceled OCO #{order_list_id} (status: {resp["listOrderStatus"]})')
         qty = sum((float(rep['executedQty']) for rep in resp['orderReports']))
         return True, qty
     except BinanceAPI.ApiError as exc:
         CColors.eprint(f'OCO order cancel failed with {exc.data}')
         return False, 0
Beispiel #3
0
 async def start(self):
     """ start trading, only call this method after locking in a pair """
     CColors.iprint(
         f'Market manager started with pair {self.api.pair["symbol"]}')
     async with aiohttp.ClientSession() as client:
         # buy <bcoin> immediately at market price, get qty. and avg. price
         succ, self.bqty, self.bprice = await self.api.buy_coin_market(
             client, self.qqty)
         if not succ:
             return
         self.tprice = (1 + self.env.profit / 100) * self.bprice
         self.sprice = (1 + self.env.stop / 100) * self.bprice
         # check sell amount eligibility at this point
         await self.check_sell_eligibility(client)
         # sell bought <bcoin> with <profit>% profit
         await self.sell_coins(client)
 def market_order_status(self, resp: dict) -> (float, float):
     """ print market order status and return executed qty and average fill price
         <resp>: response object from `req` """
     bcoin, qcoin = self.pair['baseAsset'], self.pair['quoteAsset']
     bqty, qqty = float(resp["executedQty"]), float(resp["cummulativeQuoteQty"])
     CColors.iprint(f'Executed market order (status: {resp["status"]})')
     if resp['side'] == 'BUY':
         print(f'Bought {self.bfmt(bqty)} {bcoin} with {self.qfmt(qqty)} {qcoin}')
     else:
         print(f'Sold {self.bfmt(bqty)} {bcoin} for {self.qfmt(qqty)} {qcoin}')
     print('Fills:')
     avg_price = 0
     for fill in resp['fills']:
         price, qty = float(fill['price']), float(fill['qty'])
         avg_price += price * qty / bqty
         print(f'  {self.bfmt(qty)} {bcoin} at {self.qfmt(price)} {qcoin} ' + \
                     f'(fee: {fill["commission"]} {fill["commissionAsset"]})')
     print(f'Average fill price: {self.qfmt(avg_price)} {qcoin}')
     if not avg_price:
         raise CException('Average fill price seems to be zero')
     return bqty, avg_price
    async def sell_coin_limit(self, client: aiohttp.ClientSession,
                              bqty: float, price: float) -> int:
        """ sell <bqty> of <bcoin>, return order ID (0 = fail) """
        bcoin = self.pair['baseAsset']
        CColors.cprint(f'[LIMIT SELL] Selling {self.bfmt(bqty)} {bcoin} at {self.qfmt(price)}',
                       CColors.WARNING)

        params = {
            'symbol': self.pair['symbol'],
            'side': 'SELL',
            'type': 'LIMIT',
            'timeInForce': 'GTC', # good till cancelled
            'quantity': self.bfmt(bqty),
            'price': self.qfmt(price),
        }
        try:
            _, resp = await self.req(client, 'POST', 'order', params, {})
            CColors.iprint(f'Executed limit sell order (status: {resp["status"]})')
        except BinanceAPI.ApiError as exc:
            CColors.eprint(f'Limit sell failed with {exc.data}')
            return 0
        return resp['orderId']
async def main():
    """ Entrypoint """
    klen = 241  # 4h remanence
    thresh = 5, 900  # 5% positive price fluctuation, 900% positive volume fluctuation
    min_vol = 0.1  # do not alert under 0.1 executed quote volume (tuned for BTC)
    min_chg = 0.1  # minimum acceptable price change, regardless of volume
    limits = KlineLimits(*thresh, min_vol, min_chg)

    env = Environment('.env')
    api = BinanceAPI(env)
    wapi = BinanceWSAPI(env)

    # fetch symbols to track
    qsymbols = await quote_symbols(api)
    qvalues = qsymbols.values()
    symb_names = [symb['symbol'] for symb in qvalues]
    qlen = len(qvalues)
    CColors.iprint(
        f'DawnSpotter online.\nTracking {qlen} pairs: {", ".join(symb_names)}')

    # prepare the kline data structure
    manager = KlineManager(qvalues, klen, limits)
    # Pull historical data from the API
    maxrun = 1200 // (qlen + 41)
    print(
        f'Pulling historical data from REST API, do not rerun this more than {maxrun}x/min!'
    )
    async with aiohttp.ClientSession() as client:
        coros = (api.last_klines(client, '1m', klen, symbol)
                 for symbol in qvalues)
        preconf = await asyncio.gather(*coros)
    manager.fill(zip(symb_names, preconf))

    # read trade data from WS
    print('Updating data from WebSockets...')
    async for tdata in wapi.klines_bulk(symb_names, '1m'):
        manager.update(tdata['data']['k'])
    async def sell_coin_oco(self, client: aiohttp.ClientSession,
                            bqty: float, price: float, sprice: float) -> int:
        """ sell <bqty> of <bcoin> as OCO, return order ID (0 = fail) """
        bcoin = self.pair['baseAsset']
        msg = f'[OCO SELL] Selling {self.bfmt(bqty)} {bcoin} at {self.qfmt(price)}' + \
              f', stop: {self.qfmt(sprice)}'
        CColors.cprint(msg, CColors.WARNING)

        params = {
            'symbol': self.pair['symbol'],
            'side': 'SELL',
            'quantity': self.bfmt(bqty),
            'price': self.qfmt(price),
            'stopPrice': self.qfmt(sprice),
            'stopLimitPrice': self.qfmt(sprice * 0.98),
            'stopLimitTimeInForce': 'GTC' # good till cancelled
        }
        try:
            _, resp = await self.req(client, 'POST', 'order/oco', params, {})
            CColors.iprint(f'Executed OCO order (status: {resp["listOrderStatus"]})')
        except BinanceAPI.ApiError as exc:
            CColors.eprint(f'OCO sell failed with {exc.data}')
            return 0
        return resp['orderListId']