def lock(self, bcoin: str): """ lock in a trade pair and notify main thread InvalidPair => bad pair/try again, Exception => abort on success notify a waiting thread to call `start` """ self.mut1.acquire() # reject if locked if self.locked: self.mut1.release() raise CException('Market operation is already running!') # retry if bad coin is turned in if bcoin not in self.pairs: self.mut1.release() raise InvalidPair( f'Trading pair {bcoin}/{self.env.qcoin} not found') self.locked = True self.mut1.release() # lock in a trading pair self.api.set_pair(self.pairs[bcoin]) self.use_oco = self.env.stop > -100 and self.api.pair['ocoAllowed'] if self.env.stop > -100 and not self.api.pair['ocoAllowed']: CColors.wprint( 'You set a stop price but this trading pair doesn\'t allow OCO trades!' ) # notify worker with self.cvar: self.ready = True self.cvar.notify()
async def read(self, uri: str): """ subscribe to a single stream and yield data on reception """ url = urllib.parse.urljoin(self.url, uri) while True: try: async with websockets.connect(url, ssl=True) as wsock: while True: yield json.loads(await wsock.recv()) except websockets.exceptions.WebSocketException as exc: CColors.wprint(f'WebSockets error, attempting to reconnect: {exc}')
async def bailout(self): """ bailout and immediately cancel current order and sell coins """ if not self.allow_bailout: return async with aiohttp.ClientSession() as client: # Cancel limit orders if any if self.oid: await self.cancel_limit(client, self.oid) # Sell everything on market immediately CColors.wprint('Selling on market immediately!') succ, _, price = await self.api.sell_coin_market(client, self.bqty) if succ: self.sell_market_report(price)
async def check_sell_eligibility(self, client: aiohttp.ClientSession): """ check if you can sell with your strategy """ avg = await self.api.avg_price(client) if self.env.sell_type == SellType.MARKET: low, high = self.api.qty_bound(avg, True) else: # adjust profit/loss targets plow, phigh = self.api.price_bound(avg) self.tprice = min(self.tprice, phigh) low, high = self.api.qty_bound(self.tprice) if self.use_oco: self.sprice = max(self.sprice, plow) low, _ = self.api.qty_bound(self.sprice) if not low <= self.bqty <= high: raise CException( 'Sell quantity out of allowed bounds, cannot sell!') if not low * 1.1 <= self.bqty <= high * 0.9: CColors.wprint('Caution, you are nearing Binance\'s quantity limits, ' + \ 'high price fluctuations might prohibit your sell!')
async def setup(api: BinanceAPI) -> (dict, float): """ main parameter setup return exchange info and quote amount to sell """ env = api.env def set_stdin(prompt: str, default): if not env.override: return default ret = input(prompt) return ret if ret else default prompt = f'Enter quote coin symbol (coin to trade for) [default: {env.qcoin}]: ' env.qcoin = set_stdin(prompt, env.qcoin).upper() async with aiohttp.ClientSession() as client: info, lbals = await asyncio.gather(api.exchange_info(client), api.balances(client)) symbols, src_symbols, usd_symbol = api.quote_symbols(info) bals = filter_balances(lbals, [env.qcoin] + env.src_coins) if env.qcoin not in bals: raise CException('Quote coin is invalid') qbal, qloc = bals[env.qcoin] del bals[env.qcoin] print( f'Your free balance for {env.qcoin} is {ffmt(qbal)} (locked: {ffmt(qloc)})' ) def_qty = env.buy_perc / 100 * qbal if env.usd_value: # fixed USD quote balance feature usd_price = await quote_qty_from_usd(client, api, usd_symbol) qqty = env.usd_value / usd_price while qqty > qbal: diff = 1.02 * (qqty - qbal) qbal += await buy_from_source(client, api, src_symbols, bals, diff) else: prompt = f'Enter {env.qcoin} amount to sell ' + \ f'[default: {ffmt(def_qty)} ({env.buy_perc:.2f}%)]: ' qqty = float(set_stdin(prompt, def_qty)) if qqty <= 0: raise CException( f'Cannot sell non-positive amount of {env.qcoin}') if qqty > qbal: raise CException('Insufficient quote balance') prompt = f'Enter sell type (LIMIT|MARKET) [default: {env.sell_type.name}]: ' env.sell_type = SellType(set_stdin(prompt, env.sell_type)) prompt = f'Enter desired profit in % [default: {env.profit:.2f}]: ' env.profit = float(set_stdin(prompt, env.profit)) if env.profit <= 0: CColors.wprint( 'You have set a non-positive profit. Proceeding may net you a loss!' ) prompt = f'Enter stop level in % to manage risk [default: {env.stop:.2f}]: ' env.stop = float(set_stdin(prompt, env.stop)) if not -100 <= env.stop < env.profit: raise CException('Stop percentage must be lower than profits!') print('---- SELECTED OPTIONS ----') print(f'Selected quote coin: {env.qcoin}') print(f'Selected quote amount to sell: {ffmt(qqty)} {env.qcoin} ' + \ f'(available: {ffmt(qbal)} {env.qcoin})') print(f'Selected sell strategy: {env.sell_type.name}') print(f'Selected target profit: {env.profit:.2f}%') print(f'Selected stop percentage: {env.stop:.2f}%') print('--------------------------') return symbols, qqty