Esempio n. 1
0
class Binance(Exchange):
    SOCKET = "wss://stream.binance.com:9443/ws/reefusdt@kline_1m"
    client = None

    async def connect(self, api_key: str, api_secret: str):
        self.client = Client(api_key, api_secret)

    async def buy(self, quantity: str, symbol: str, price: float):
        self.client.create_order(symbol=symbol,
                                 side=SIDE_BUY,
                                 type=ORDER_TYPE_MARKET,
                                 quantity=quantity)

    async def sell(self, quantity: str, symbol: str, price: float):
        self.client.create_order(symbol=symbol,
                                 side=SIDE_SELL,
                                 type=ORDER_TYPE_MARKET,
                                 quantity=quantity)

    async def start_socket(self):
        ws = websocket.WebSocketApp(self.SOCKET, on_message=self.on_message)
        ws.run_forever()

    async def on_message(self, ws, message) -> ExchangeMessage:
        json_message = json.loads(message)

        print(json_message)

        candle = json_message['k']
        is_candle_closed = candle['x']
        close = candle['c']

        return ExchangeMessage(symbol='REEFUSDT',
                               is_candle_closed=is_candle_closed,
                               close=close)
    def handle(self, *args, **options):
        c = Client(settings.BINANCE_API_KEY, settings.BINANCE_SECRET)
        assets = c.get_all_tickers()
        for asset in assets:
            coin, crt = Coin.objects.get_or_create(symbol=asset['symbol'])
            coin.btc_price = asset['price']
            coin.save()

            trading_orders = TradingCondition.objects.filter(closed=False,
                                                             coin=coin)
            for tc in trading_orders:

                # Calculate price change in percentage. IF AutoSell or StopLoss
                # is triggered - sell coins.

                change = round((tc.coin.btc_price - tc.btc_buy_price) /
                               tc.btc_buy_price * 100, 2)
                tc.change = change

                if change >= tc.auto_sell:
                    # Send market SELL order
                    print("AUTO SELL!", coin.symbol, tc.btc_buy_price,
                          tc.coin.btc_price, change)
                    c = Client(tc.trader.api_key, tc.trader.secret)
                    order_result = c.create_order(symbol=coin.symbol,
                                                  side='SELL',
                                                  type='MARKET',
                                                  quantity=tc.quantity)
                    print(order_result)
                    tc.closed = True

                elif change <= -tc.stop_loss:
                    # Send market SELL order
                    print("STOP LOSS!", coin.symbol, tc.btc_buy_price,
                          tc.coin.btc_price, change)
                    c = Client(tc.trader.api_key, tc.trader.secret)
                    order_result = c.create_order(symbol=coin.symbol,
                                                  side='SELL',
                                                  type='MARKET',
                                                  quantity=tc.quantity)
                    print(order_result)
                    tc.closed = True

                tc.save()

        print("Prices updated!")
def order(side,symble,quantity,order_type):
    try:
        print("sending order")
        order = Client.create_order(symble=symble,side=side,type=order_type,quantity=quantity)
        print(order)
    except Exception as e:
        return False
    return True
Esempio n. 4
0
def Order(side, quantity, symbol, order_type=ORDER_TYPE_MARKET):
    global asset_qauntity
    client = Client(config.binance_api_key, config.binance_secret_key)
    try:
        last_message = "sending order"
        order_with_info = client.create_order(symbol=symbol, side=side, type=order_type, quantity=asset_qauntity)
        #print(order_with_info)
    except Exception as e:
        #print("an exception occured - {}".format(e))
        return False
    return True
def order(side, quantity, symbol, order_type=ORDER_TYPE_MARKET):
    client = Client(ApiSettings.query.filter_by(id=1).first().API_KEY,
                    ApiSettings.query.filter_by(id=1).first().SECRET_KEY)
    try:
        print(f"sending order {order_type} - {side} {quantity} {symbol}")
        order = client.create_order(symbol=symbol, side=side, type=order_type, quantity=quantity)
    except Exception as e:
        print(f"an exception occured - {e}")
        result = e
        logs_to_file(side, quantity, ticker, tv_price, result)
        return False
    return order
Esempio n. 6
0
def binance_create_order(chat_id, **params):
    full_api = getbinanceapi(chat_id)['binance_api']
    api_key = full_api.split(':')[0].strip()
    api_secret = full_api.split(':')[1].strip()
    client = Client(api_key, api_secret)
    binance_timesync(client)
    try:
        js_info = client.create_order(**params)
        return js_info
    except Exception as e:
        print(e)
        return str(e)
Esempio n. 7
0
def order(side, quantity, symbol, order_type=ORDER_TYPE_MARKET):
    try:
        client = Client(config.API_KEY, config.API_SECRET)
        order = client.create_order(symbol=symbol,
                                    side=side,
                                    type=order_type,
                                    quantity=quantity)
        print(order)
        return True
    except Exception as e:
        print(e)
        print("ERROR ORDERING")
        return False
    return True
Esempio n. 8
0
def make_multiplier_sell(client: Client, symbol: str, amount: float, multiplier: float):
    print(f"selling {symbol} at {amount} * {multiplier}")
    order = client.create_order(
        symbol=symbol,
        side=SIDE_SELL,
        type=ORDER_TYPE_TAKE_PROFIT,
        stopPrice=amount * multiplier)
    # order = client.create_test_order(
    #     symbol=symbol,
    #     side=SIDE_SELL,
    #     type=ORDER_TYPE_TAKE_PROFIT,
    #     stopPrice=amount * multiplier)

    return order
    def market_buy_order(self, _amount, _symbol):
        client = Client(keys['api_key'], keys['api_secret'], tld="us")
        try:
            buy_order = client.create_order(symbol=_symbol,
                                            side=Client.SIDE_BUY,
                                            type=Client.ORDER_TYPE_MARKET,
                                            quantity=_amount)

        except Exception as e:
            print(e)
            with open('order_message_log.txt', 'a') as message_entry:
                message_entry.write(
                    f'{_index} SELL {_symbol} \n\n ERROR OCCURED {e} \n\n')

        return buy_order
Esempio n. 10
0
class BinanceTrade:

    #定义基本属性
    def __init__(self):
        self.binance = Client(ACCESS_KEY, SECRET_KEY)

    def place_order(self, order):
        try:
            data = self.binance.create_order(
                    symbol = order.contract_id,
                    side = order.side,
                    type = order.order_type,
                    timeInForce = order.time_in_force,
                    quantity = order.quantity,
                    price = order.price)
            order.order_id = str(data['orderId'])
            order.client_order_id = data['clientOrderId']
        except (BinanceAPIException, BinanceRequestException) as e:
            order.err_code = 1
            order.err_msg = str(e)
        except:
            order.err_code = 2
            order.err_msg = str(sys.exc_info())
        if order.err_code != 0:
            logger.debug(order.err_msg)

    def cancel_order(self, order):
            pass

    def get_order(self, order):
        data = self.binance.get_order(
                symbol = order.security,
                orderId = order.order_id)
        if float(data['executedQty']) != order.executed_amount:
            pass
        if data['status'] == 'CANCELED':
            pass
        if data['status'] == 'FILLED' or data['status'] == 'CANCELED':
            self.is_complete = True

    def get_account(self):
        data_dic = self.binance.get_account()
        print(data_dic)
Esempio n. 11
0
class BinanceAPI(API):
    def __init__(self):
        api_key = "rOsVSRe409vOsHGnwpErHivGTsAqCHNxZoNnocvYnuhBCX1iAbBnTsiKSh5hBmyV"
        api_secret = "d7zvWZBktLsFJVp8T5g6Q8koLQUPPr8GEwBu41Dfgame25r8L8zbtpuTuzE2gRAh"
        self.client = Client(api_key, api_secret)

        self.allowedTickers = ["BTCUSDT", "ETHUSDT", "BTCETH"]

    def check_allowed_ticker(self, ticker):
        return ticker in self.allowedTickers

    def create_order(self, ticker, quantity, side, orderType, price=0):

        sideAPI = Client.SIDE_SELL if side == "SELL" else Client.SIDE_BUY if side == "BUY" else None
        typeAPI = Client.ORDER_TYPE_MARKET if orderType == "MARKET" else Client.ORDER_TYPE_LIMIT if orderType == "LIMIT" else None

        if sideAPI == None: raise Exception("Side not allowed")
        if typeAPI == None: raise Exception("Type not allowed")

        order = self.client.create_order(symbol=ticker,
                                         side=sideAPI,
                                         type=typeAPI,
                                         quantity=quantity)

        return True

    def get_all_tickers_prices(self):
        return self.client.get_all_tickers()

    def get_order_book(self, symbol):
        # get market depth
        return self.client.get_order_book(symbol=symbol)

    def get_historical_data(self, symbol, interval, startDate, endDate):

        startDate = startDate.strftime("%d %b, %Y")
        endDate = endDate.strftime("%d %b, %Y")

        if interval == '15':
            APIInterval = Client.KLINE_INTERVAL_15MINUTE

        return self.client.get_historical_klines(symbol, APIInterval,
                                                 startDate, endDate)
Esempio n. 12
0
def place_order(coin, amount):
    client = Client("BINANCE HASH", "SECRET HASH")
    order = client.create_order(
        symbol=coin + 'BTC',
        side=Client.SIDE_BUY,
        type=Client.ORDER_TYPE_MARKET,
        quantity=int(
            float(amount) / float(
                json.loads(
                    requests.get(
                        "https://api.binance.com/api/v3/ticker/price?symbol=" +
                        coin + "BTC").text)["price"])))

    price = float(
        json.loads(
            requests.get(
                "https://api.binance.com/api/v3/ticker/price?symbol=" + coin +
                "BTC").text)["price"])
    balance = json.loads(client.get_asset_balance(asset=coin)["free"])

    order = client.order_limit_sell(symbol=coin + 'BTC',
                                    quantity=int(balance),
                                    price=f"{2*price:.8f}")
Esempio n. 13
0
                
    
coinA_balance = int(float(client.get_asset_balance("coinA").get("free")))
coinB_balance = float(client.get_asset_balance("coinB").get("free"))



Side = "sell"  # depending on the situation, change this with "sell" or "buy"

while True:
    while Side == "sell":
        coinA_last_price = float(client.get_symbol_ticker(symbol="coinA symbol").get("price"))
        coinB_last_price = float(client.get_symbol_ticker(symbol="coinB symbol").get("price"))
        
        if coinA_last_price > you decide and coinB_last_price > you decide:  # change you decide with a float
            client.create_order(symbol="coinA symbol", side="SELL", type="MARKET",
                                quantity=coinA_balance)  # sell all coinA
            
            coinA_balance = int(float(client.get_asset_balance("coinA").get("free")))
            coinB_balance = float(client.get_asset_balance("coinB").get("free"))

            email_conn = smtplib.SMTP(host, port)
            email_conn.ehlo()
            email_conn.starttls()
            email_conn.login(username, password)
            email_conn.sendmail(from_email, to_mail, 
                                "you sold")
            email_conn.quit()
            Side = "buy"
        sleep(30)  # seconds
    
    while Side == "buy":
class BinanceExchange(Exchange):
    exchange_name = "Binance"
    isMargin = False

    def __init__(self, apiKey, apiSecret, pairs, name):
        super().__init__(apiKey, apiSecret, pairs, name)

        self.connection = Client(self.api['key'], self.api['secret'])

        symbol_info_arr = self.connection.get_exchange_info()
        dict_symbols_info = {
            item['symbol']: item
            for item in symbol_info_arr["symbols"]
        }
        actual_symbols_info = {
            symbol: dict_symbols_info[symbol]
            for symbol in self.pairs
        }
        self.symbols_info = actual_symbols_info

        self.update_balance()
        self.socket = BinanceSocketManager(self.connection)
        self.socket.start_user_socket(self.on_balance_update)
        self.socket.start()
        self.is_last_order_event_completed = True
        self.step_sizes = {}
        self.balance_updated = True

        for symbol_info in symbol_info_arr['symbols']:
            if symbol_info['symbol'] in self.pairs:
                self.step_sizes[symbol_info['symbol']] = \
                    [f['stepSize'] for f in symbol_info['filters'] if f['filterType'] == 'LOT_SIZE'][0]

    def start(self, caller_callback):
        self.socket.start_user_socket(caller_callback)

    def update_balance(self):
        account_information = self.connection.get_account()
        self.set_balance(account_information['balances'])

    def get_trading_symbols(self):
        symbols = set()
        if not self.symbols_info:
            raise RuntimeError("Cant get exchange info")
        for key, value in self.symbols_info.items():
            symbols.add(value["quoteAsset"])
            symbols.add(value["baseAsset"])
        return symbols

    def set_balance(self, balances):
        symbols = self.get_trading_symbols()
        dict_balances = {item['asset']: item for item in balances}
        actual_balance = {symbol: dict_balances[symbol] for symbol in symbols}
        self.balance = actual_balance

    def on_balance_update(self, upd_balance_ev):
        if upd_balance_ev['e'] == 'outboundAccountPosition':
            balance = []
            for ev in upd_balance_ev['B']:
                balance.append({
                    'asset': ev['a'],
                    'free': ev['f'],
                    'locked': ev['l']
                })
            self.balance.update({item['asset']: item for item in balance})

    def get_open_orders(self):
        orders = self.connection.get_open_orders()
        general_orders = []
        for o in orders:
            quantityPart = self.get_part(o['symbol'], o["origQty"], o['price'],
                                         o['side'])
            general_orders.append(
                Order(o['price'], o["origQty"], quantityPart, o['orderId'],
                      o['symbol'], o['side'], o['type'], self.exchange_name))
        return general_orders

    def _cancel_order(self, order_id, symbol):
        self.connection.cancel_order(symbol=symbol, orderId=order_id)
        self.logger.info(f'{self.name}: Order canceled')

    async def on_cancel_handler(self, event: Actions.ActionCancel):
        try:
            slave_order_id = self._cancel_order_detector(event.price)
            self._cancel_order(slave_order_id, event.symbol)
        except BinanceAPIException as error:
            self.logger.error(f'{self.name}: error {error.message}')
        except:
            self.logger.error(
                f"{self.name}: error in action: {event.name} in slave {self.name}"
            )

    def stop(self):
        self.socket.close()

    def _cancel_order_detector(self, price):
        # detect order id which need to be canceled
        slave_open_orders = self.connection.get_open_orders()
        for ordr_open in slave_open_orders:
            if float(ordr_open['price']) == float(price):
                return ordr_open['orderId']

    def process_event(self, event):
        # return event in generic type from websocket

        # if this event in general type it was send from start function and need call firs_copy
        if 'exchange' in event:
            return event

        if event['e'] == 'outboundAccountPosition':
            self.on_balance_update(event)

        elif event['e'] == 'executionReport':
            if event['X'] == 'FILLED':
                return
            elif event['x'] == 'CANCELED':
                return Actions.ActionCancel(event['s'], event['p'], event['i'],
                                            self.exchange_name, event)
            elif event['X'] == 'NEW':
                order_event = event

                if order_event['s'] not in self.pairs:
                    return

                if order_event[
                        'o'] == 'MARKET':  # if market order, we haven't price and cant calculate quantity
                    order_event['p'] = self.connection.get_ticker(
                        symbol=order_event['s'])['lastPrice']

                # part = self.get_part(order_event['s'], order_event['q'], order_event['p'], order_event['S'])

                # shortcut mean https://github.com/binance-exchange/binance-official-api-docs/blob/master/user-data-stream.md#order-update
                order = Order(
                    order_event['p'], order_event['q'],
                    self.get_part(order_event['s'], order_event['q'],
                                  order_event['p'], order_event['S']),
                    order_event['i'], order_event['s'], order_event['S'],
                    order_event['o'], self.exchange_name, order_event['P'])
                return Actions.ActionNewOrder(order, self.exchange_name, event)
            return

    async def on_order_handler(self, event: Actions.ActionNewOrder):
        self.create_order(event.order)

    def create_order(self, order):
        """
        :param order:
        """
        quantity = self.calc_quantity_from_part(order.symbol,
                                                order.quantityPart,
                                                order.price, order.side)
        self.logger.info('Slave ' + self.name + ' ' +
                         str(self._get_quote_balance(order.symbol)) + ' ' +
                         str(self._get_base_balance(order.symbol)) +
                         ', Create Order:' + ' amount: ' + str(quantity) +
                         ', price: ' + str(order.price))
        try:
            if order.type == 'STOP_LOSS_LIMIT' or order.type == "TAKE_PROFIT_LIMIT":
                self.connection.create_order(symbol=order.symbol,
                                             side=order.side,
                                             type=order.type,
                                             price=order.price,
                                             quantity=quantity,
                                             timeInForce='GTC',
                                             stopPrice=order.stop)
            if order.type == 'MARKET':
                self.connection.create_order(symbol=order.symbol,
                                             side=order.side,
                                             type=order.type,
                                             quantity=quantity)
            else:
                self.connection.create_order(symbol=order.symbol,
                                             side=order.side,
                                             type=order.type,
                                             quantity=quantity,
                                             price=order.price,
                                             timeInForce='GTC')
            self.logger.info(f"{self.name}: order created")
        except Exception as e:
            self.logger.error(str(e))

    def _get_quote_balance(self, symbol):
        return self.balance[self.symbols_info[symbol]['quoteAsset']]

    def _get_base_balance(self, symbol):
        return self.balance[self.symbols_info[symbol]['baseAsset']]

    def get_part(self, symbol: str, quantity: float, price: float, side: str):
        # get part of the total balance of this coin

        # if order[side] == sell: need obtain coin balance
        if side == 'BUY':
            get_context_balance = self._get_quote_balance
            market_value = float(quantity) * float(price)
        else:
            get_context_balance = self._get_base_balance
            market_value = float(quantity)

        balance = float(get_context_balance(symbol)['free'])

        # if first_copy the balance was update before
        if self.balance_updated:
            balance += float(get_context_balance(symbol)['locked'])
        # else:
        #     balance += market_value

        part = market_value / balance
        part = part * 0.99  # decrease part for 1% for avoid rounding errors in calculation
        return part

    def calc_quantity_from_part(self, symbol, quantityPart, price, side):
        # calculate quantity from quantityPart

        # if order[side] == sell: need obtain coin balance

        if side == 'BUY':
            get_context_balance = self._get_quote_balance
            buy_koef = float(price)
        else:
            get_context_balance = self._get_base_balance
            buy_koef = 1

        cur_bal = float(get_context_balance(symbol)['free'])

        if self.balance_updated:
            cur_bal += float(get_context_balance(symbol)['locked'])

        quantity = quantityPart * cur_bal / buy_koef

        stepSize = float(self.step_sizes[symbol])
        precision = int(round(-math.log(stepSize, 10), 0))
        quantity = round(quantity, precision)
        return quantity
Esempio n. 15
0
from binance.client import Client
from lamda import *

client = Client(AK, AS)

# get market depth
depth = client.get_order_book(symbol='BNBBTC')

# place market buy order
from binance.enums import *
order = client.create_order(symbol='BNBBTC',
                            side=SIDE_BUY,
                            type=ORDER_TYPE_MARKET,
                            quantity=100)

# get all symbol prices
prices = client.get_all_tickers()

# withdraw 100 ETH
# check docs for assumptions around withdrawals
from binance.exceptions import BinanceApiException, BinanceWithdrawException
try:
    result = client.withdraw(asset='ETH', address='<eth_address>', amount=100)
except BinanceApiException as e:
    print(e)
except BinanceWithdrawException as e:
    print(e)
else:
    print("Success")

# fetch list of withdrawals
Esempio n. 16
0
watched = db.watched
binance_client = Client(settings.BINANCE_API_KEY, settings.BINANCE_SECRET)

while True:
    payload = {}
    for coin_watched in watched.find():
        current_price = prices.find_one({"s": coin_watched['s']})['c']
        buy_price = Decimal(coin_watched['buy'])
        change = round((Decimal(current_price) - buy_price) / buy_price \
                                                                * 100, 2)
        if change >= int(coin_watched['sell']) or \
           change <= -int(coin_watched['stop']):

            watched.delete_one({"tc": coin_watched['tc']})
            payload[int(coin_watched['tc'])] = ["SOLD", str(change)]

            try:
                o_r = binance_client.create_order(symbol=coin_watched['s'],
                                                  side='SELL',
                                                  type='MARKET',
                                                  quantity=coin_watched['q'])
                print(o_r)

            except BinanceAPIException as e:
                print(binance_client.get_account())
                print(e, coin_watched)
        else:
            payload[int(coin_watched['tc'])] = [current_price, str(change)]

    channel_layer.send("prices", {"text": json.dumps(payload)})
    time.sleep(0.5)
Esempio n. 17
0
                     "o": open_order_count,
                     "t": trade_count
                 })
             if open_order_count < 1 and trade_count < 5:
                 print('PASSED')
                 all_rules_passed = True
 if all_rules_passed:
     print('buy...............................')
     order_number = 999999999
     buy_price = round(Decimal(price), 8)
     try:
         print('AMOUNT:        %(a)s' % {"a": amount})
         print('PRICE:         %(a)s' % {"a": buy_price})
         print('SYMBOL:        %(a)s' % {"a": symbol})
         buy = client.create_order(symbol=symbol,
                                   side=Client.SIDE_BUY,
                                   type=Client.ORDER_TYPE_MARKET,
                                   quantity=amount)
         print(buy)
         time.sleep(1)
         order_number = buy["orderId"]
         opened = False
         final_price = buy_price
         if buy["status"] == 'filled':
             opened = True
             final_price = buy['fills'][0]['price']
         insert_cmd = """
 INSERT INTO set_trades_binance (
   currencypair,
   rate,
   amount,
   btc_value,
Esempio n. 18
0
class BinanceClient(AbstractClient):
    def __init__(self, listener):
        self.exchange = 'binance'
        self.trade_fee = Decimal(0.0005)
        self.client = Client(api_keys.binance[0], api_keys.binance[1])
        super(BinanceClient, self).__init__(listener)
        self._get_exchange_info()
        self.get_all_balances()

    def _buy(self, symbol, price, amount):
        result = self.client.create_order(symbol=symbol,
                                          quantity=amount,
                                          price=price,
                                          side=SIDE_BUY,
                                          type=ORDER_TYPE_LIMIT,
                                          timeInForce=TIME_IN_FORCE_GTC)
        self.open_orders[symbol] = result['orderId']

    def _sell(self, symbol, price, amount):
        result = self.client.create_order(symbol=symbol,
                                          quantity=amount,
                                          price=price,
                                          side=SIDE_SELL,
                                          type=ORDER_TYPE_LIMIT,
                                          timeInForce=TIME_IN_FORCE_GTC)
        self.open_orders[symbol] = result['orderId']

    def _cancel(self, symbol):
        orderId = self.open_orders.pop(symbol)
        try:
            self.client.cancel_order(symbol=symbol, orderId=orderId)
        # Binance throws API exception if the order is not open so we'll have to check if it's fulfilled here.
        except BinanceAPIException as e:
            time.sleep(1)
            if not self.is_order_fulfilled(symbol, orderId):
                # Order was not fulfilled, re-throw exception
                raise e
        except BinanceRequestException as e:
            self.errors += 1
            raise e

    def is_order_fulfilled(self, symbol, orderId):
        try:
            for data in self.client.get_my_trades(symbol=symbol):
                if data['orderId'] == int(orderId):
                    return True

        except (BinanceRequestException, BinanceAPIException) as e:
            print datetime.now(), "[Binance] is order fulfilled error", e
            self.errors += 1

        return False

    def get_all_balances(self):
        try:
            result = self.client.get_account()

            for balance in result['balances']:
                self.coin_balances[str(balance['asset'])] = Decimal(
                    str(balance['free']))  # + Decimal(balance['locked'])

            return self.coin_balances

        except (BinanceRequestException, BinanceAPIException) as e:
            print datetime.now(), "[Binance] get all balances error:", str(
                e).replace('\r\n', '')
            self.errors += 1

    def _market_poll(self):
        result = {'success': False}
        result['client'] = self
        result['timestamp'] = int(time.time() * 1000)
        result['coinpairs'] = {}

        try:
            coins = self.client.get_orderbook_tickers()

            for coin in coins:
                symbol = str(coin['symbol'])
                if symbol in self.exchange_symbols:
                    result['coinpairs'][self._get_arbitrager_coinpair(
                        symbol)] = {
                            'buy': Decimal(str(coin['bidPrice'])),
                            'buyAmount': Decimal(str(coin['bidQty'])),
                            'sell': Decimal(str(coin['askPrice'])),
                            'sellAmount': Decimal(str(coin['askQty']))
                        }

        except (BinanceRequestException, BinanceAPIException) as e:
            print datetime.now(), "[Binance] market poll error", str(
                e).replace('\r\n', '')
            self.errors += 1

        if len(result['coinpairs']) > 0:
            result['success'] = True

        return result

    def _get_exchange_info(self):
        result = self.client.get_exchange_info()
        for symbol in result['symbols']:
            sym = str(symbol['symbol'])
            self.trade_rules[sym] = {}
            trade_rule = self.trade_rules[sym]
            for filter in symbol['filters']:
                if filter['filterType'] == 'PRICE_FILTER':
                    trade_rule['minPrice'] = Decimal(filter['minPrice'])
                    trade_rule['maxPrice'] = Decimal(filter['maxPrice'])
                    trade_rule['stepPrice'] = Decimal(filter['tickSize'])
                elif filter['filterType'] == 'LOT_SIZE':
                    if sym == 'NEOETH':
                        trade_rule['minAmount'] = Decimal(0.1)
                    elif sym == 'LTCETH':
                        trade_rule['minAmount'] = Decimal(0.05)
                    else:
                        trade_rule['minAmount'] = Decimal(filter['minQty'])
                    trade_rule['maxAmount'] = Decimal(filter['maxQty'])
                    trade_rule['stepAmount'] = Decimal(filter['stepSize'])
                elif filter['filterType'] == 'MIN_NOTIONAL':
                    trade_rule['minNotional'] = Decimal(filter['minNotional'])
Esempio n. 19
0
class BinanceApi(object):
    def __init__(self, api_key, api_secret, order_currency, payment_currency):
        self.api_key = api_key
        self.api_secret = api_secret
        self.client = Client(self.api_key, self.api_secret)
        self.bsm = BinanceSocketManager(client=self.client)
        self.orders = {}
        self.asset_balance = {}
        self.order_currency = order_currency
        self.payment_currency = payment_currency
        self.symbol = self.order_currency + self.payment_currency
        self.current_price = {}
        self.current_depth = {}
        self.bsm.start_symbol_ticker_socket(self.symbol,
                                            self._process_ticker_message)
        self.bsm.start_depth_socket(self.symbol, self._process_depth_message,
                                    BinanceSocketManager.WEBSOCKET_DEPTH_5)
        self.bsm.start_user_socket(self._process_user_info_message)
        self.bsm.start()
        self._set_asset_balance()

    def _process_ticker_message(self, msg):
        self.current_price = {
            "price": float(msg['c']),
            "timestamp": time.time() * 1000
        }
        #print self.current_price

    def _process_depth_message(self, msg):
        asks_depth = []
        bids_depth = []
        for ask in msg['asks']:
            asks_depth.append({
                "price": float(ask[0]),
                "quantity": float(ask[1])
            })
        for bid in msg['bids']:
            bids_depth.append({
                "price": float(bid[0]),
                "quantity": float(bid[1])
            })
        self.current_depth = {
            "asks": asks_depth,
            "bids": bids_depth,
            "timestamp": time.time() * 1000
        }
        #print self.current_depth

    def _process_user_info_message(self, msg):
        #print msg
        if msg['e'].encode('utf-8') == "outboundAccountInfo":
            '''TODO: 用户数据入库'''
            found = 0
            for balance in msg['B']:
                if balance['a'].encode('utf-8') == self.order_currency:
                    self.asset_balance[self.order_currency] = {
                        "free": float(balance['f']),
                        "locked": float(balance['l'])
                    }
                    found += 1
                elif balance['a'].encode('utf-8') == self.payment_currency:
                    self.asset_balance[self.payment_currency] = {
                        "free": float(balance['f']),
                        "locked": float(balance['l'])
                    }
                    found += 1
                elif found >= 2:
                    break
                else:
                    continue
            conn.execute('INSERT INTO asset_info  VALUES (?,?,?,?,?,?)', [
                str(uuid.uuid1()),
                self.asset_balance[self.order_currency]['free'] +
                self.asset_balance[self.order_currency]['locked'], 0.0,
                self.asset_balance[self.payment_currency]['free'] +
                self.asset_balance[self.payment_currency]['locked'], 'binance',
                time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            ])
            conn.commit()
        elif msg['e'].encode('utf-8') == "executionReport":
            if not self.orders.has_key(msg['i']):
                time.sleep(1)
            self.orders[msg['i']]['status'] = msg['X'].encode('utf-8')
            if msg['X'].encode('utf-8') in ["FILLED", "PARTIALLY_FILLED"]:
                trade = {
                    'trade_id':
                    msg['t'],
                    'commission':
                    float(msg['n']),
                    'commissionAsset':
                    msg['N'].encode('utf-8'),
                    'price':
                    float(msg['L']),
                    'quantity':
                    float(msg['l']),
                    'order_id':
                    msg['i'],
                    'date_time':
                    time.strftime("%Y-%m-%d %H:%M:%S",
                                  time.localtime(msg['T'] / 1000))
                }
                self.orders[msg['i']]['trades'][trade['trade_id']] = trade

                self.orders[msg['i']]['deal_quantity'] += trade['quantity']
                self.orders[msg['i']][
                    'deal_amount'] += trade['quantity'] * trade['price']
                self.orders[msg['i']]['deal_fee'] += trade['commission']
                '''手续费记录方式可能会存在问题,多币种咋办'''
                if self.orders[
                        msg['i']]['fee_asset'] != trade['commissionAsset']:
                    self.orders[msg['i']][
                        'fee_asset'] += trade['commissionAsset'] + ' '
                self.orders[msg['i']]['deal_price'] = self.orders[msg['i']][
                    'deal_amount'] / self.orders[msg['i']]['deal_quantity']

    def _set_asset_balance(self):
        tries = 0
        '''sleep?'''
        while tries < 5:
            try:
                asset = self.client.get_asset_balance(self.payment_currency)
            except BinanceAPIException as e:
                print e.code, e.message
                tries += 1
                continue
            if asset is not None:
                self.asset_balance[asset['asset']] = {
                    "free": float(asset['free']),
                    'locked': float(asset['locked'])
                }
                break
            time.sleep(0.5)
        if tries == 5:
            print "get asset balance failed! "
            return

        tries = 0
        while tries < 5:
            try:
                asset = self.client.get_asset_balance(self.order_currency)
            except BinanceAPIException as e:
                print e.code, e.message
                tries += 1
                continue
            if asset is not None:
                self.asset_balance[asset['asset']] = {
                    "free": float(asset['free']),
                    'locked': float(asset['locked'])
                }
                break
            time.sleep(0.5)
        if tries == 5:
            print "get asset balance failed! "
            return

    def get_current_price(self):
        return self.current_price

    def get_current_depth(self):
        return self.current_depth

    def create_order(self, side, price, quantity):
        try:
            order_info = self.client.create_order(
                symbol=self.symbol,
                side=side,
                type=ORDER_TYPE_LIMIT,
                price=str(price),
                quantity=quantity,
                timeInForce=TIME_IN_FORCE_GTC)
        except BinanceAPIException as e:
            return -1, {"code": e.code, "message": e.message}

        self.orders[order_info['orderId']] = {
            "side":
            side,
            "order_quantity":
            float(order_info['origQty']),
            "symbol":
            self.symbol,
            "order_price":
            float(order_info['price']),
            "status":
            order_info['status'].encode('utf-8'),
            'date_time':
            time.strftime("%Y-%m-%d %H:%M:%S",
                          time.localtime(order_info['transactTime'] / 1000)),
            'deal_quantity':
            0,
            'order_amount':
            float(order_info['price']) * float(order_info['origQty']),
            'deal_amount':
            0,
            'deal_fee':
            0,
            'fee_asset':
            '',
            'deal_price':
            0,
            'trades': {}
        }

        return order_info['orderId'], self.orders[order_info['orderId']]

    '''def order_buy(self, price, quantity, order_type=ORDER_TYPE_LIMIT):
        if order_type is ORDER_TYPE_LIMIT:
            try:
                order = self.client.order_limit_buy(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}
        else:
            try:
                order = self.client.order_market_buy(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}

        self.orders[order['orderId']] = {"side": "bid", "executedQty": [], "origQty": float(order['origQty']), "currency": self.symbol,
                                         "price": float(order['price']), "status": order['status'].encode('utf-8')}
        return order['orderId'], self.orders[order['orderId']]

    def order_sell(self, price, quantity, order_type=ORDER_TYPE_LIMIT):
        if order_type is ORDER_TYPE_LIMIT:
            try:
                order = self.client.order_limit_sell(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}
        else:
            try:
                order = self.client.order_market_sell(symbol=self.symbol, quantity=quantity, price=str(price))
            except BinanceAPIException as e:
                return -1, {"code": e.code, "message": e.message}

        #self.orders[order_id] = "NEW"
        self.orders[order['orderId']] = {"side": "ask", "executedQty": [], "origQty": float(order['origQty']),"symbol": self.symbol,
                                         "price": float(order['price']), "status": order['status'].encode('utf-8')}
        return order['orderId'], self.orders[order['orderId']]'''

    def order_cancel(self, order_id):
        try:
            result = self.client.cancel_order(symbol=self.symbol,
                                              orderId=order_id)
        except BinanceAPIException as e:
            return -1, {"code": e.code, "message": e.message}
        #self.orders[result['orderId']]["status"] = "CANCELED"
        return result['orderId'], self.orders[result['orderId']]

    def get_order_info(self, order_id):
        if self.orders.has_key(order_id):
            if abs(self.orders[order_id]['order_quantity'] -
                   self.orders[order_id]['deal_quantity']) < 0.0001:
                self.orders[order_id]['status'] = 'FILLED'
            elif self.orders[order_id]['deal_quantity'] == 0:
                self.orders[order_id]['status'] = 'PARTIALLY_FILLED'
            return self.orders[order_id]
        return None

    def check_balance(self, currency):
        return self.asset_balance[currency]

    def get_asset_balance(self):
        return self.asset_balance

    def get_all_trade(self, order_id):
        return self.client.get_my_trades(symbol=self.symbol)

    def get_symbol_info(self, symbol):
        return self.client.get_symbol_info(symbol=symbol)
Esempio n. 20
0
class Binance(object):
    def __init__(self):
        print("-- Connecting to binance ...")
        self.client = Client(os.environ['BINANCE_API_KEY'],
                             os.environ['BINANCE_API_SECRET'])

    def get_balance(self, coin):
        print("-- Getting balance for " + coin)
        assetJSON = self.client.get_asset_balance(coin)
        return float(assetJSON['free'])

    def get_price(self, coin, coinfrom):
        priceJSON = self.client.get_symbol_ticker(symbol=coin + coinfrom)
        return float(priceJSON['price'])

    def buy_market(self, coin, coinfrom, ignored, quantity, testmode):
        print("-- Buying market " + str(quantity) + " " + coin + " from " +
              coinfrom)
        self.symbol = coin + coinfrom
        if testmode:
            print("[TEST] " + str(quantity) + " " + coin + " buy at : " +
                  str(ignored) + " " + coinfrom +
                  " (price is ignored on Binance)")
        else:
            orderBuy = self.client.create_order(
                symbol=coin + coinfrom,
                side=self.client.SIDE_BUY,
                type=self.client.ORDER_TYPE_MARKET,
                # timeInForce=clientBinance.TIME_IN_FORCE_GTC,
                quantity=quantity,
                # price=repr(originalPrice)
            )

            completed = False
            while not completed:
                time.sleep(0.2)
                self.orderID = orderBuy['clientOrderId']
                orderBuySt = self.client.get_order(symbol=coin + coinfrom,
                                                   orderId=self.orderID)
                print("+ Order buy status : " + orderBuySt['status'] +
                      " at : " + orderBuySt['price'])

                if not orderBuySt == self.client.ORDER_STATUS_NEW:
                    completed = True

    def sell_market(self, coin, coinTo, ignored, quantity, testmode):
        print("-- Selling market " + str(quantity) + " " + coin + " to " +
              coinTo)
        if testmode:
            print("[TEST] " + str(quantity) + " " + coin + " sell at : " +
                  str(ignored) + " " + coinTo +
                  " (price is ignored on Binance)")
        else:
            orderSell = self.client.create_test_order(
                symbol=coin + coinTo,
                side=self.client.SIDE_SELL,
                type=self.client.ORDER_TYPE_MARKET,
                # timeInForce=clientBinance.TIME_IN_FORCE_GTC,
                quantity=quantity,
                # price=repr(newPrice)
            )

            completed = False
            while not completed:
                time.sleep(0.2)
                orderSellId = orderSell['clientOrderId']
                orderSellSt = self.client.get_order(symbol=coin + coinTo,
                                                    orderId=orderSellId)
                print("+ Order sell status : " + orderSellSt['status'] +
                      " at : " + orderSellSt['price'])

                if not orderSellSt == self.client.ORDER_STATUS_NEW:
                    completed = True

    def cancel_order(self):
        print("-- Canceling order")
        self.client.cancel_order(symbol=self.symbol, orderId=self.orderID)
        self.symbol = None
        self.orderID = None
class BinanceAPIManager:
    def __init__(self, config: Config, db: Database, logger: Logger):
        # initializing the client class calls `ping` API endpoint, verifying the connection
        self.binance_client = Client(
            config.BINANCE_API_KEY,
            config.BINANCE_API_SECRET_KEY,
            tld=config.BINANCE_TLD,
        )
        self.db = db
        self.logger = logger
        self.config = config

        self.cache = BinanceCache()
        self.stream_manager: Optional[BinanceStreamManager] = None
        self.setup_websockets()

    def setup_websockets(self):
        self.stream_manager = BinanceStreamManager(
            self.cache,
            self.config,
            self.binance_client,
            self.logger,
        )

    @cached(cache=TTLCache(maxsize=1, ttl=43200))
    def get_trade_fees(self) -> Dict[str, float]:
        return {
            ticker["symbol"]: float(ticker["takerCommission"])
            for ticker in self.binance_client.get_trade_fee()
        }

    @cached(cache=TTLCache(maxsize=1, ttl=60))
    def get_using_bnb_for_fees(self):
        return self.binance_client.get_bnb_burn_spot_margin()["spotBNBBurn"]

    def get_fee(self, origin_coin: Coin, target_coin: Coin, selling: bool):
        base_fee = self.get_trade_fees()[origin_coin + target_coin]
        if not self.get_using_bnb_for_fees():
            return base_fee

        # The discount is only applied if we have enough BNB to cover the fee
        amount_trading = (self._sell_quantity(origin_coin.symbol,
                                              target_coin.symbol)
                          if selling else self._buy_quantity(
                              origin_coin.symbol, target_coin.symbol))

        fee_amount = amount_trading * base_fee * 0.75
        if origin_coin.symbol == "BNB":
            fee_amount_bnb = fee_amount
        else:
            origin_price = self.get_ticker_price(origin_coin + Coin("BNB"))
            if origin_price is None:
                return base_fee
            fee_amount_bnb = fee_amount * origin_price

        bnb_balance = self.get_currency_balance("BNB")

        if bnb_balance >= fee_amount_bnb:
            return base_fee * 0.75
        return base_fee

    def get_account(self):
        """
        Get account information
        """
        return self.binance_client.get_account()

    def get_ticker_price(self, ticker_symbol: str):
        """
        Get ticker price of a specific coin
        """
        price = self.cache.ticker_values.get(ticker_symbol, None)
        if price is None and ticker_symbol not in self.cache.non_existent_tickers:
            self.cache.ticker_values = {
                ticker["symbol"]: float(ticker["price"])
                for ticker in self.binance_client.get_symbol_ticker()
            }
            self.logger.debug(
                f"Fetched all ticker prices: {self.cache.ticker_values}")
            price = self.cache.ticker_values.get(ticker_symbol, None)
            if price is None:
                self.logger.info(
                    f"Ticker does not exist: {ticker_symbol} - will not be fetched from now on"
                )
                self.cache.non_existent_tickers.add(ticker_symbol)

        return price

    def get_currency_balance(self, currency_symbol: str, force=False) -> float:
        """
        Get balance of a specific coin
        """
        with self.cache.open_balances() as cache_balances:
            balance = cache_balances.get(currency_symbol, None)
            if force or balance is None:
                cache_balances.clear()
                cache_balances.update({
                    currency_balance["asset"]: float(currency_balance["free"])
                    for currency_balance in self.binance_client.get_account()
                    ["balances"]
                })
                self.logger.debug(f"Fetched all balances: {cache_balances}")
                if currency_symbol not in cache_balances:
                    cache_balances[currency_symbol] = 0.0
                    return 0.0
                return cache_balances.get(currency_symbol, 0.0)

            return balance

    def retry(self, func, *args, **kwargs):
        time.sleep(1)
        attempts = 0
        while attempts < 20:
            try:
                return func(*args, **kwargs)
            except Exception:  # pylint: disable=broad-except
                self.logger.warning(
                    f"Failed to Buy/Sell. Trying Again (attempt {attempts}/20)"
                )
                if attempts == 0:
                    self.logger.warning(traceback.format_exc())
                attempts += 1
        return None

    def get_symbol_filter(self, origin_symbol: str, target_symbol: str,
                          filter_type: str):
        return next(_filter for _filter in self.binance_client.get_symbol_info(
            origin_symbol + target_symbol)["filters"]
                    if _filter["filterType"] == filter_type)

    @cached(cache=TTLCache(maxsize=2000, ttl=43200))
    def get_alt_tick(self, origin_symbol: str, target_symbol: str):
        step_size = self.get_symbol_filter(origin_symbol, target_symbol,
                                           "LOT_SIZE")["stepSize"]
        if step_size.find("1") == 0:
            return 1 - step_size.find(".")
        return step_size.find("1") - 1

    @cached(cache=TTLCache(maxsize=2000, ttl=43200))
    def get_min_notional(self, origin_symbol: str, target_symbol: str):
        return float(
            self.get_symbol_filter(origin_symbol, target_symbol,
                                   "MIN_NOTIONAL")["minNotional"])

    def _wait_for_order(
        self, order_id, origin_symbol: str, target_symbol: str
    ) -> Optional[BinanceOrder]:  # pylint: disable=unsubscriptable-object
        while True:
            order_status: BinanceOrder = self.cache.orders.get(order_id, None)
            if order_status is not None:
                break
            self.logger.debug(f"Waiting for order {order_id} to be created")
            time.sleep(1)

        self.logger.debug(f"Order created: {order_status}")

        while order_status.status != "FILLED":
            try:
                order_status = self.cache.orders.get(order_id, None)

                self.logger.debug(f"Waiting for order {order_id} to be filled")

                if self._should_cancel_order(order_status):
                    cancel_order = None
                    while cancel_order is None:
                        cancel_order = self.binance_client.cancel_order(
                            symbol=origin_symbol + target_symbol,
                            orderId=order_id)
                    self.logger.info("Order timeout, canceled...")

                    # sell partially
                    if order_status.status == "PARTIALLY_FILLED" and order_status.side == "BUY":
                        self.logger.info("Sell partially filled amount")

                        order_quantity = self._sell_quantity(
                            origin_symbol, target_symbol)
                        partially_order = None
                        while partially_order is None:
                            partially_order = self.binance_client.order_market_sell(
                                symbol=origin_symbol + target_symbol,
                                quantity=order_quantity)

                    self.logger.info("Going back to scouting mode...")
                    return None

                if order_status.status == "CANCELED":
                    self.logger.info(
                        "Order is canceled, going back to scouting mode...")
                    return None

                time.sleep(1)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.info(f"Unexpected Error: {e}")
                time.sleep(1)

        self.logger.debug(f"Order filled: {order_status}")
        return order_status

    def wait_for_order(
        self, order_id, origin_symbol: str, target_symbol: str,
        order_guard: OrderGuard
    ) -> Optional[BinanceOrder]:  # pylint: disable=unsubscriptable-object
        with order_guard:
            return self._wait_for_order(order_id, origin_symbol, target_symbol)

    def _should_cancel_order(self, order_status):
        minutes = (time.time() - order_status.time / 1000) / 60
        timeout = 0

        if order_status.side == "SELL":
            timeout = float(self.config.SELL_TIMEOUT)
        else:
            timeout = float(self.config.BUY_TIMEOUT)

        if timeout and minutes > timeout and order_status.status == "NEW":
            return True

        if timeout and minutes > timeout and order_status.status == "PARTIALLY_FILLED":
            if order_status.side == "SELL":
                return True

            if order_status.side == "BUY":
                current_price = self.get_ticker_price(order_status.symbol)
                if float(current_price) * (1 - 0.001) > float(
                        order_status.price):
                    return True

        return False

    def buy_alt(self, origin_coin: Coin, target_coin: Coin) -> BinanceOrder:
        return self.retry(self._buy_alt, origin_coin, target_coin)

    def _buy_quantity(self,
                      origin_symbol: str,
                      target_symbol: str,
                      target_balance: float = None,
                      from_coin_price: float = None):
        target_balance = target_balance or self.get_currency_balance(
            target_symbol)
        from_coin_price = from_coin_price or self.get_ticker_price(
            origin_symbol + target_symbol)

        origin_tick = self.get_alt_tick(origin_symbol, target_symbol)
        return math.floor(target_balance * 10**origin_tick /
                          from_coin_price) / float(10**origin_tick)

    @staticmethod
    def float_as_decimal_str(num: float):
        return f"{num:0.08f}".rstrip("0").rstrip(
            ".")  # remove trailing zeroes too

    def _make_order(
        self,
        side: str,
        symbol: str,
        quantity: float,
        price: float,
        quote_quantity: float,
    ):
        params = {
            "symbol":
            symbol,
            "side":
            side,
            "quantity":
            self.float_as_decimal_str(quantity),
            "type":
            self.config.BUY_ORDER_TYPE
            if side == Client.SIDE_BUY else self.config.SELL_ORDER_TYPE,
        }
        if params["type"] == Client.ORDER_TYPE_LIMIT:
            params["timeInForce"] = self.binance_client.TIME_IN_FORCE_GTC
            params["price"] = self.float_as_decimal_str(price)
        elif side == Client.SIDE_BUY:
            del params["quantity"]
            params["quoteOrderQty"] = self.float_as_decimal_str(quote_quantity)
        return self.binance_client.create_order(**params)

    def _buy_alt(self, origin_coin: Coin, target_coin: Coin):
        """
        Buy altcoin
        """
        trade_log = self.db.start_trade_log(origin_coin, target_coin, False)
        origin_symbol = origin_coin.symbol
        target_symbol = target_coin.symbol

        with self.cache.open_balances() as balances:
            balances.clear()

        origin_balance = self.get_currency_balance(origin_symbol)
        target_balance = self.get_currency_balance(target_symbol)
        from_coin_price = self.get_ticker_price(origin_symbol + target_symbol)

        order_quantity = self._buy_quantity(origin_symbol, target_symbol,
                                            target_balance, from_coin_price)
        self.logger.info(f"BUY QTY {order_quantity} of <{origin_symbol}>")

        # Try to buy until successful
        order = None
        order_guard = self.stream_manager.acquire_order_guard()
        while order is None:
            try:
                order = self._make_order(
                    side=Client.SIDE_BUY,
                    symbol=origin_symbol + target_symbol,
                    quantity=order_quantity,
                    quote_quantity=target_balance,
                    price=from_coin_price,
                )
                self.logger.info(order)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.warning(f"Unexpected Error: {e}")

        executed_qty = float(order.get("executedQty", 0))
        if executed_qty > 0 and order["status"] == "FILLED":
            order_quantity = executed_qty  # Market buys provide QTY of actually bought asset

        trade_log.set_ordered(origin_balance, target_balance, order_quantity)

        order_guard.set_order(origin_symbol, target_symbol,
                              int(order["orderId"]))
        order = self.wait_for_order(order["orderId"], origin_symbol,
                                    target_symbol, order_guard)

        if order is None:
            return None

        self.logger.info(f"Bought {origin_symbol}")

        trade_log.set_complete(order.cumulative_quote_qty)

        return order

    def sell_alt(self, origin_coin: Coin, target_coin: Coin) -> BinanceOrder:
        return self.retry(self._sell_alt, origin_coin, target_coin)

    def _sell_quantity(self,
                       origin_symbol: str,
                       target_symbol: str,
                       origin_balance: float = None):
        origin_balance = origin_balance or self.get_currency_balance(
            origin_symbol)

        origin_tick = self.get_alt_tick(origin_symbol, target_symbol)
        return math.floor(origin_balance * 10**origin_tick) / float(
            10**origin_tick)

    def _sell_alt(self, origin_coin: Coin, target_coin: Coin):
        """
        Sell altcoin
        """
        trade_log = self.db.start_trade_log(origin_coin, target_coin, True)
        origin_symbol = origin_coin.symbol
        target_symbol = target_coin.symbol

        with self.cache.open_balances() as balances:
            balances.clear()

        origin_balance = self.get_currency_balance(origin_symbol)
        target_balance = self.get_currency_balance(target_symbol)
        from_coin_price = self.get_ticker_price(origin_symbol + target_symbol)

        order_quantity = self._sell_quantity(origin_symbol, target_symbol,
                                             origin_balance)
        self.logger.info(f"Selling {order_quantity} of {origin_symbol}")

        self.logger.info(f"Balance is {origin_balance}")
        order = None
        order_guard = self.stream_manager.acquire_order_guard()
        while order is None:
            try:
                order = self._make_order(
                    side=Client.SIDE_SELL,
                    symbol=origin_symbol + target_symbol,
                    quantity=order_quantity,
                    quote_quantity=target_balance,
                    price=from_coin_price,
                )
                self.logger.info(order)
            except BinanceAPIException as e:
                self.logger.info(e)
                time.sleep(1)
            except Exception as e:  # pylint: disable=broad-except
                self.logger.warning(f"Unexpected Error: {e}")

        self.logger.info("order")
        self.logger.info(order)

        trade_log.set_ordered(origin_balance, target_balance, order_quantity)

        order_guard.set_order(origin_symbol, target_symbol,
                              int(order["orderId"]))
        order = self.wait_for_order(order["orderId"], origin_symbol,
                                    target_symbol, order_guard)

        if order is None:
            return None

        new_balance = self.get_currency_balance(origin_symbol)
        while new_balance >= origin_balance:
            new_balance = self.get_currency_balance(origin_symbol, True)

        self.logger.info(f"Sold {origin_symbol}")

        trade_log.set_complete(order.cumulative_quote_qty)

        return order
Esempio n. 22
0
 continue
 #sell
 if (sell_price < float(bids3[2][0])):
     if ((order_ask_quantity > 0) and
         (order_ask_quantity <
          (float(bids3[0][1]) + float(bids3[1][1]) + float(bids3[2][1])))):
         notify_str = 'SELL EOS price: ' + bids3[2][
             0] + ' quantity: ' + str(order_ask_quantity)
         logging.warn(notify_str)
         last_price = float(bids3[2][0])
         store_price(last_price)
         sell_count += 1
         store_sell_count(sell_count)
         response = client.create_order(symbol=trade_pairs,
                                        side='SELL',
                                        type='LIMIT',
                                        quantity=order_ask_quantity,
                                        price=float(bids3[2][0]),
                                        timeInForce='GTC')
         logging.warn(response)
         notify("Notify", notify_str)
         #mqttc.publish(PUB_TOPIC,payload=notify_str,qos=0)
     else:
         if (order_ask_quantity > 0):
             sleep_time = 5
 #buy
 if (buy_price > float(asks3[2][0])):
     if ((order_bid_quantity > 0) and
         (order_bid_quantity <
          (float(asks3[0][1]) + float(asks3[1][1]) + float(asks3[2][1])))):
         notify_str = 'BUY EOS price: ' + asks3[2][0] + ' quantity: ' + str(
             order_bid_quantity)
Esempio n. 23
0
        print("Decreasing")
        time.sleep(20)
        continue
    else:
        print("Creasing")

    if (symbolPrice < ma50 * 0.995):
        print("DINAMIC_BUY")

        try:

            buyOrder = client.create_order(symbol=symbolTicker,
                                           side='BUY',
                                           type='STOP_LOSS_LIMIT',
                                           quantity=1.5,
                                           price=round(symbolPrice * 1.0055,
                                                       7),
                                           stopPrice=round(
                                               symbolPrice * 1.005, 7),
                                           timeInForce='GTC')

            auxPrice = symbolPrice
            time.sleep(3)
            while orderStatus(buyOrder) == 'NEW':

                # BEGIN GET PRICE
                try:
                    list_of_tickers = client.get_all_tickers()
                except Exception as e:
                    with open("BNBBTC_scalper.txt", "a") as myfile:
                        myfile.write(
Esempio n. 24
0
class BinanceStore(with_metaclass(MetaSingleton, object)):
    _GRANULARITIES = {
        (TimeFrame.Minutes, 1): '1m',
        (TimeFrame.Minutes, 3): '3m',
        (TimeFrame.Minutes, 5): '5m',
        (TimeFrame.Minutes, 15): '15m',
        (TimeFrame.Minutes, 30): '30m',
        (TimeFrame.Minutes, 60): '1h',
        (TimeFrame.Minutes, 120): '2h',
        (TimeFrame.Minutes, 240): '4h',
        (TimeFrame.Minutes, 360): '6h',
        (TimeFrame.Minutes, 480): '8h',
        (TimeFrame.Minutes, 720): '12h',
        (TimeFrame.Days, 1): '1d',
        (TimeFrame.Days, 3): '3d',
        (TimeFrame.Weeks, 1): '1w',
        (TimeFrame.Months, 1): '1M',
    }

    BrokerCls = None  # Broker class will autoregister
    DataCls = None  # Data class will auto register

    @classmethod
    def getdata(cls, *args, **kwargs):
        """Returns ``DataCls`` with args, kwargs"""
        return cls.DataCls(*args, **kwargs)

    @classmethod
    def getbroker(cls, *args, **kwargs):
        """Returns broker with *args, **kwargs from registered ``BrokerCls``"""
        return cls.BrokerCls(*args, **kwargs)

    def __init__(self,
                 api_key,
                 api_secret,
                 coin_refer,
                 coin_target,
                 retries=5):
        self.binance = Client(api_key, api_secret)
        self.binance_socket = BinanceSocketManager(self.binance)
        self.coin_refer = coin_refer
        self.coin_target = coin_target
        self.retries = retries

        self._precision = None
        self._step_size = None

        self._cash = 0
        self._value = 0
        self.get_balance()

    def retry(method):
        @wraps(method)
        def retry_method(self, *args, **kwargs):
            for i in range(self.retries):
                time.sleep(500 / 1000)  # Rate limit
                try:
                    return method(self, *args, **kwargs)
                except BinanceAPIException:
                    if i == self.retries - 1:
                        raise

        return retry_method

    @retry
    def cancel_order(self, order_id):
        try:
            self.binance.cancel_order(symbol=self.symbol, orderId=order_id)
        except BinanceAPIException as api_err:
            if api_err.code == -2011:  # Order filled
                return
            else:
                raise api_err
        except Exception as err:
            raise err

    @retry
    def create_order(self, side, type, size, price):
        return self.binance.create_order(symbol=self.symbol,
                                         side=side,
                                         type=type,
                                         timeInForce=TIME_IN_FORCE_GTC,
                                         quantity=self.format_quantity(size),
                                         price=self.strprecision(price))

    @retry
    def close_open_orders(self):
        orders = self.binance.get_open_orders(symbol=self.symbol)
        for o in orders:
            self.cancel_order(o['orderId'])

    def format_quantity(self, size):
        precision = self.step_size.find('1') - 1
        if precision > 0:
            return '{:0.0{}f}'.format(size, precision)
        return floor(int(size))

    @retry
    def get_asset_balance(self, asset):
        balance = self.binance.get_asset_balance(asset)
        return float(balance['free']), float(balance['locked'])

    def get_balance(self):
        free, locked = self.get_asset_balance(self.coin_target)
        self._cash = free
        self._value = free + locked

    def get_interval(self, timeframe, compression):
        return self._GRANULARITIES.get((timeframe, compression))

    def get_precision(self):
        symbol_info = self.get_symbol_info(self.symbol)
        self._precision = symbol_info['baseAssetPrecision']

    def get_step_size(self):
        symbol_info = self.get_symbol_info(self.symbol)
        for f in symbol_info['filters']:
            if f['filterType'] == 'LOT_SIZE':
                self._step_size = f['stepSize']

    @retry
    def get_symbol_info(self, symbol):
        return self.binance.get_symbol_info(symbol)

    @property
    def precision(self):
        if not self._precision:
            self.get_precision()
        return self._precision

    def start_socket(self):
        if self.binance_socket.is_alive():
            return

        self.binance_socket.daemon = True
        self.binance_socket.start()

    @property
    def step_size(self):
        if not self._step_size:
            self.get_step_size()

        return self._step_size

    def stop_socket(self):
        self.binance_socket.close()
        reactor.stop()
        self.binance_socket.join()

    def strprecision(self, value):
        return '{:.{}f}'.format(value, self.precision)

    @property
    def symbol(self):
        return '{}{}'.format(self.coin_refer, self.coin_target)
Esempio n. 25
0
    def trades(self):
        client = Client(api_key, api_secret)
        asset = "BNB"
        balance= (client.get_asset_balance('BTC'))
        balance = float(balance['free'])
        startBalance=(client.get_asset_balance('BTC'))
        startBalance= float(startBalance['free'])
        #lastPrice = float(Orders.get_ticker(symbol)['lastPrice'])
        currentPrice = client.get_ticker(symbol='BNBBTC')
        currentPrice=float(currentPrice['lastPrice'])
        firstBuyPrice = .00118

        numberOfBuys =0
        balances = client.get_account()
       

        lowCertainty = firstBuyPrice * 0.95
        highCertainty = firstBuyPrice * 1.0
        sellCertainty = firstBuyPrice * 1.1

        buylowCertainty= float(round((balance* 0.05)/currentPrice))
        buyhighCertainty= float(round((balance * 0.10)/currentPrice))
        sellhighCertainty= float(round(balance * 0.95))

        lowCounter= 0
        highCounter= 0
        sellcounter = 0

        cycle = 0
        actions = []

        

        print colored('Auto Trading with binance', "cyan")
  

        
        while balance>= (startBalance/2):
            if lowCounter < 1:
                if currentPrice >= lowCertainty and currentPrice< highCertainty:
                    order = client.create_order(
                    symbol='BNBBTC',
                    side= Client.SIDE_BUY,
                    type=Client.ORDER_TYPE_MARKET,
                    quantity=buylowCertainty
                )
                    firstBuyPrice = currentPrice
                    print colored('bought at low certainty', "blue")
                    balance= (client.get_asset_balance('BTC'))
                    balance = float(balance['free'])
                    lowCounter= lowCounter +1
            elif highCounter < 1:
                elif currentPrice >= highCertainty:
                    order = client.create_order(
                    symbol='BNBBTC',
                    side= Client.SIDE_BUY,
                    type=Client.ORDER_TYPE_MARKET,
                    quantity=buyhighCertainty
                    )
                    firstBuyPrice = currentPrice
                    print colored('bought at high certainty', "blue")
                    highCounter = highCounter + 1
                    balance= (client.get_asset_balance('BTC'))
                    balance = float(balance['free'])
                elif currentPrice >= sellCertainty:
                    order = client.order_market_sell(
                    symbol='BNBBTC',
                    quantity=sellhighCertainty)
                    print colored('sold at high certainty', "blue")
                    sellcounter= sellcounter + 1
                    balance= (client.get_asset_balance('BTC'))
                    balance = float(balance['free'])
Esempio n. 26
0
class Market:
    def __init__(self):
        self.client = Client(api_key=apiKey, api_secret=apiSecret, tld='us')

    def buy_coin_possible(self, symbol, percentOfEquity):
        # Get equity amount of our USD, BTC, ETH
        accountValue = float(self.client.get_asset_balance("USD")["free"])
        accountValue += float(
            self.client.get_asset_balance("BTC")["free"]) * float(
                self.client.get_symbol_ticker(symbol="BTCUSD")["price"])
        accountValue += float(
            self.client.get_asset_balance("ETH")["free"]) * float(
                self.client.get_symbol_ticker(symbol="ETHUSD")["price"])

        # calculate how much of the symbol that is
        moneyToSpend = percentOfEquity * accountValue / 100.0
        symbolQuantity = moneyToSpend / float(
            self.client.get_symbol_ticker(symbol=symbol)["price"])

        # get recent trades to see current volatility
        recentTrades = self.client.get_recent_trades(symbol=symbol)
        lastTrade = {}
        totalSum = 0
        weightedSum = 0
        for trade in recentTrades:
            if lastTrade == {} or int(trade["time"]) > int(lastTrade["time"]):
                lastTrade = trade
            totalSum += float(trade["qty"])
            weightedSum += float(trade["price"]) * float(trade["qty"])
        weightedAvg = weightedSum / totalSum

        # calculate the price we should strive for with current volatility
        symbolQtyAdjustedBefore = symbolQuantity * (1.0 - takerFee)
        symbolQtyAdjustedAfter = symbolQtyAdjustedBefore * (1.0 - takerFee)
        endProfitPrice = 0
        if weightedAvg > float(lastTrade["price"]):
            endProfitPrice = weightedAvg + (weightedAvg -
                                            float(lastTrade["price"])) * .5
        else:
            endProfitPrice = float(
                lastTrade["price"]) + abs(weightedAvg -
                                          float(lastTrade["price"])) * .5

        # calculate stop loss at 3 : 1 risk ratio using expected profit
        expectedProfit = (endProfitPrice * symbolQtyAdjustedAfter) - (
            float(lastTrade["price"]) * symbolQtyAdjustedAfter)
        if expectedProfit <= 0:
            return
        stopLossPrice = float(lastTrade["price"]) - expectedProfit * (1 / 3)
        # possibleLoss = (stopLossPrice * symbolQtyAdjusted) - (float(lastTrade["price"]) * symbolQtyAdjusted) # for reference

        # set the limit buy so we get it at the price we want hopefully
        order = None
        try:
            order = self.client.order_limit_buy(
                symbol=symbol,
                quantity="{:0.0{}f}".format(symbolQuantity, 3),
                price="{:0.0{}f}".format(
                    float(lastTrade["price"]) +
                    float(lastTrade["price"]) * .001, 2),
            )
        except exceptions.BinanceAPIException as e:
            print(e)
            return

        # wait 3 seconds.  usually small orders will go through immediately but if this scales it wouldn't
        time.sleep(5)

        # see if it went through at our price, otherwise cancel it
        if order is not None:
            for openOrder in self.client.get_open_orders():
                if order["orderId"] == openOrder["orderId"]:
                    self.client.cancel_order(symbol=symbol,
                                             orderId=order["orderId"])
                    return

        try:
            # set our end/expected price for this trade
            self.client.order_limit_sell(
                symbol=symbol,
                quantity="{:0.0{}f}".format(symbolQtyAdjustedBefore, 3),
                price="{:0.0{}f}".format(endProfitPrice, 2))

            self.client.create_order(
                symbol=symbol,
                side=Client.SIDE_SELL,
                type=Client.ORDER_TYPE_STOP_LOSS_LIMIT,
                quantity="{:0.0{}f}".format(symbolQtyAdjustedBefore, 3),
                price="{:0.0{}f}".format(stopLossPrice, 2),
                stopPrice="{:0.0{}f}".format(stopLossPrice + .01, 2),
                timeInForce=Client.TIME_IN_FORCE_GTC)
        except exceptions.BinanceAPIException as e:
            print(e)
            return

    def get_symbol_price(self, symbol):
        recentTrades = self.client.get_recent_trades(symbol=symbol)
        lastTrade = {}

        for trade in recentTrades:
            if lastTrade == {} or int(trade["time"]) > int(lastTrade["time"]):
                lastTrade = trade

        return float(lastTrade["price"])

    def get_account_value(self):
        valueInUSD = 0.0
        usdBalance = self.client.get_asset_balance("USD")
        valueInUSD = valueInUSD + float(usdBalance["free"]) + float(
            usdBalance["locked"])
        time.sleep(.1)

        ethBalance = self.client.get_asset_balance("ETH")
        ethPrice = self.get_symbol_price("ETHUSD")
        valueInUSD = valueInUSD + float(ethBalance["free"]) * ethPrice + float(
            ethBalance["locked"]) * ethPrice
        time.sleep(.1)

        btcBalance = self.client.get_asset_balance("BTC")
        btcPrice = self.get_symbol_price("BTCUSD")
        valueInUSD = valueInUSD + float(btcBalance["free"]) * btcPrice + float(
            btcBalance["locked"]) * btcPrice
        time.sleep(.1)

        return valueInUSD
Esempio n. 27
0
from binance.client import Client
from binance.websockets import BinanceSocketManager
from twisted.internet import reactor

api_key = "WK8dITaZRDlJ2DRSjxZdrHbuvMRhSafCls8WdhGrmNArF3FoSxUmjlto3iTOvWDU"
api_secret = "acEjoqKOJ0TNlVYoZgDYrKVIYvStBfxAmCJG90rj3GYi7jlOJzwqqcAeLcLZN4BK"

client = Client(api_key, api_secret)

client.API_URL = 'https://testnet.binance.vision/api'
#print(client.get_asset_balance(asset='ETH'))
print(client.get_account())

try:
    order = client.create_order(
        symbol='ETHUSDT',
        side=Client.SIDE_BUY,
        type=Client.ORDER_TYPE_MARKET,
        quantity=1,
    )

except BinanceAPIException as e:
    # error handling goes here
    print(e)
except BinanceOrderException as e:
    # error handling goes here
    print(e)

print(order)

print(client.get_asset_balance(asset='ETH'))
Esempio n. 28
0
class PriceTunnelTrader:
    def __init__(self, tunnels):
        self.bot = BotSettings.objects.all()[0]
        self.telegram_bot = telegram.Bot(token=self.bot.telegram_bot.token)
        self.tech_chat = self.bot.telegram_bot.chat.get(
            name='Binance_Tech_Vice_Trader_chat')
        self.info_chat = self.bot.telegram_bot.chat.get(
            name='Binance_Vice_Trader_chat')
        self.tunnels = tunnels
        self.client = Client(self.bot.binance_api.api_key,
                             self.bot.binance_api.api_secret)
        self.profit_threshold = self.bot.profit_threshold

    def init_trade(self, tunnel):
        new_trade = Deals.objects.create(
            base_pair=tunnel.symbol_tuple[0],
            middle_pair=tunnel.symbol_tuple[1],
            end_pair=tunnel.symbol_tuple[2],
            init_qty=tunnel.qty_final,
            expected_base_price=tunnel.price_info[0],
            expected_middle_price=tunnel.price_info[1],
            expected_end_price=tunnel.price_info[2],
            reverse=tunnel.reverse,
            expected_invest_amount=tunnel.invest_amount,
            expected_profit=tunnel.profit_abs,
            expected_return=tunnel.return_amount,
            expected_roi=tunnel.roi)
        self.place_base_order(new_trade)

    def place_base_order(self, trade):
        order = self.client.create_order(symbol=trade.base_pair,
                                         side='BUY',
                                         type='LIMIT',
                                         timeInForce='IOC',
                                         quantity=1,
                                         price=1)
        if order['status'] == 'FILLED':
            trade.base_order_id = order['clientOrderId']
            trade.invest = order['cummulativeQuoteQty']
            trade.datetime_base_pair = datetime.datetime.utcfromtimestamp(
                int(order['transactTime']) /
                1000).replace(tzinfo=timezone.get_current_timezone())

            trade.save()

    def place_middle_order(self):
        pass

    def place_end_order(self):
        pass

    def _is_repeated_deal(self, symbol_tuple, price_tuple, init_qty):
        now = timezone.now()
        deals = Deals.objects.filter(
            date_open__range=(now - timezone.timedelta(minutes=1), now))
        init_hash = hash((
            symbol_tuple[0],
            symbol_tuple[1],
            symbol_tuple[2],
            price_tuple[0],
            price_tuple[1],
            price_tuple[2],
            init_qty,
        ))
        if deals:
            for deal in deals:
                check_hash = hash((
                    deal.base_pair,
                    deal.middle_pair,
                    deal.end_pair,
                    deal.base_price,
                    deal.middle_price,
                    deal.end_price,
                    deal.init_qty,
                ))
                if check_hash == init_hash:
                    return True
        return False

    def check_profit_trade(self):
        for tunnel in self.tunnels[::-1]:
            repeated_trade = self._is_repeated_deal(tunnel.symbol_tuple,
                                                    tunnel.price_info,
                                                    tunnel.qty_final)
            if tunnel.profit_abs > self.profit_threshold and tunnel.invest_amount > 10 and not repeated_trade:
                self.inform_telegram(tunnel)
                #self.init_trade(tunnel)
            #Result already sorted, if no profit, break
            elif tunnel.profit_abs > self.profit_threshold:
                continue
            else:
                break

    def inform_telegram(self, tunnel):
        deal = Deals.objects.create(
            base_pair=tunnel.symbol_tuple[0],
            middle_pair=tunnel.symbol_tuple[1],
            end_pair=tunnel.symbol_tuple[2],
            init_qty=tunnel.qty_final,
            expected_base_price=tunnel.price_info[0],
            expected_middle_price=tunnel.price_info[1],
            expected_end_price=tunnel.price_info[2],
            reverse=tunnel.reverse,
            expected_invest=tunnel.invest_amount,
            expected_return=tunnel.return_amount,
            expected_roi=tunnel.roi,
            expected_profit=tunnel.profit_abs,
            hypothetical_invest=tunnel.should_info[0],
            hypothetical_return=tunnel.should_info[1],
            hypothetical_profit=tunnel.should_info[2],
        )

        message = '''Есть сделка в плюс
ROI = {0} %
Ожидаемый профит = {1} $ 
Схема = {2}
Инвест = {3} $
Возврат = {4} $
'''.format(round(tunnel.roi, 2), round(tunnel.profit_abs, 8),
           tunnel.symbol_tuple, round(tunnel.invest_amount, 8),
           round(tunnel.return_amount, 8))
        while True:
            try:
                #print(tunnel)
                self.telegram_bot.send_message(self.tech_chat.chat_id, message)
            except:
                continue
            break
class TriangularArbitrageModel:
    def __init__(self, base_asset, quote_asset, tertiary_asset):
        # Construct the Binance API client
        self.client = Client(os.environ.get('STELLA_API_KEY'),
                             os.environ.get('STELLA_SECRET_KEY'))

        self.base_asset = base_asset
        self.quote_asset = quote_asset
        self.tertiary_asset = tertiary_asset

        self.pair_a = (base_asset, quote_asset)
        self.pair_b = (quote_asset, tertiary_asset)
        self.pair_c = (tertiary_asset, base_asset)

        # get the valid exchange names for each pair
        self.pair_a_valid_name = valid_pair_name[self.pair_a]
        self.pair_b_valid_name = valid_pair_name[self.pair_b]
        self.pair_c_valid_name = valid_pair_name[self.pair_c]

        # determine if the valid pair needs to be inverted for our model
        self.pair_a_inversion = self.pair_a_valid_name.startswith(
            quote_asset)  #usdt/eth false
        self.pair_b_inversion = self.pair_b_valid_name.startswith(
            tertiary_asset)  #eth/btc false
        self.pair_c_inversion = self.pair_c_valid_name.startswith(
            base_asset)  # btc/usdt false

        # call get_market_data to update the data
        self.market_data = {}

        # call get_order_books to update the data
        self.order_book_limit = 100
        self.pair_a_order_book = {}
        self.pair_b_order_book = {}
        self.pair_c_order_book = {}

        self.base_asset_amount = 0
        self.pair_a_quote_fill = 0
        self.pair_b_quote_fill = 0
        self.implicit_profit = 0

        self.debounce = timedelta(
            0, 10, 0)  # 10 seconds -- decrease this when we get more advanced
        # initialize last_trade_time so we can trade immediately
        self.last_trade_time = datetime.now() - self.debounce

        # holds the last n values for implicit profit

        self.live_pair_a_fill = []
        self.live_pair_b_fill = []
        self.live_implicit_profit = []
        self.live_implicit_profit_len = 0
        self.implicit_rolling_window = 10  # smaller window to calculate for trading strategy
        self.live_window = 60

        self.trade_fee = 0.0005

        self.base_asset_account = 0
        self.quote_asset_account = 0
        self.tertiary_asset_account = 0

        # TODO: add filters for min_notional

        self.pair_a_minQty = 0
        self.pair_a_maxQty = 0
        self.pair_a_stepSize = 0
        self.pair_b_minQty = 0
        self.pair_b_maxQty = 0
        self.pair_b_stepSize = 0
        self.pair_c_minQty = 0
        self.pair_c_maxQty = 0
        self.pair_c_stepSize = 0
        self.exchangeInfo = self.update_exchange_info(
        )  # update filter information

    def async_update(self, total_base_asset, profit_conditional):
        # This method should be called periodically for executing live trading
        # TODO: get order book data from web socket streams instead of REST API
        self.update_order_books()
        self.base_asset_amount = total_base_asset
        self.pair_a_quote_fill = self._get_order_book_quote_value(
            self.pair_a_order_book, total_base_asset, self.pair_a_inversion)
        self.pair_b_quote_fill = self._get_order_book_quote_value(
            self.pair_b_order_book, self.pair_a_quote_fill,
            self.pair_b_inversion)
        self.implicit_profit = self._get_order_book_quote_value(
            self.pair_c_order_book, self.pair_b_quote_fill,
            self.pair_c_inversion)

        # update the time series for last n implicit profits
        self.live_implicit_profit_len = len(self.live_implicit_profit)

        if self.live_implicit_profit_len >= self.live_window:
            self.live_pair_a_fill.pop(0)
            self.live_pair_b_fill.pop(0)
            self.live_implicit_profit.pop(0)
        self.live_pair_a_fill.append(self.pair_a_quote_fill)
        self.live_pair_b_fill.append(self.pair_b_quote_fill)
        self.live_implicit_profit.append(self.implicit_profit)

        # CONDITIONAL FOR PLACING TRADES
        debounce_conditional = (datetime.now() - self.last_trade_time >=
                                self.debounce)
        implicit_rolling_average = self.implicit_profit
        if self.live_implicit_profit_len > self.implicit_rolling_window:
            implicit_rolling_average = sum(
                self.live_implicit_profit[-self.implicit_rolling_window:]
            ) / float(self.implicit_rolling_window)
        if debounce_conditional and (self.implicit_profit >
                                     implicit_rolling_average >
                                     profit_conditional):
            print()
            print('Implicit profit is: ', self.implicit_profit)
            print('implicit_rolling_average: ', implicit_rolling_average)
            pre_trade = datetime.now()
            print('Placing arbitrage trades', str(pre_trade))
            # self.place_arbitrage_trade(total_base_asset)
            # self.place_arbitrage_trade()
            post_trade = datetime.now()
            print('Arbitrage trades complete: ', str(post_trade))
            print('Time to complete trades: ', str(post_trade - pre_trade))
            print()
            self.last_trade_time = post_trade

        else:
            print('Trade conditional not met. Implicit profit: ',
                  self.implicit_profit)

    def update_exchange_info(self):
        exchange_info = self.client.get_exchange_info()

        for symbol in exchange_info['symbols']:
            print(symbol['symbol'])
            print(symbol['filters'])
            if symbol['symbol'] == self.pair_a_valid_name:
                self.pair_a_minQty = symbol['filters'][1]['minQty']
                self.pair_a_maxQty = symbol['filters'][1]['maxQty']
                self.pair_a_stepSize = symbol['filters'][1]['stepSize']
                print(self.pair_a_minQty)
                print(self.pair_a_maxQty)
                print(self.pair_a_stepSize)

        for symbol in exchange_info['symbols']:
            print(symbol['filters'])
            if symbol['symbol'] == self.pair_b_valid_name:
                self.pair_b_minQty = symbol['filters'][1]['minQty']
                self.pair_b_maxQty = symbol['filters'][1]['maxQty']
                self.pair_b_stepSize = symbol['filters'][1]['stepSize']
                print(self.pair_b_minQty)
                print(self.pair_b_maxQty)
                print(self.pair_b_stepSize)

        for symbol in exchange_info['symbols']:
            print(symbol['filters'])
            if symbol['symbol'] == self.pair_c_valid_name:
                self.pair_c_minQty = symbol['filters'][1]['minQty']
                self.pair_c_maxQty = symbol['filters'][1]['maxQty']
                self.pair_c_stepSize = symbol['filters'][1]['stepSize']
                print(self.pair_c_minQty)
                print(self.pair_c_maxQty)
                print(self.pair_c_stepSize)

        return exchange_info

    def test_binance_client(self):
        depth = self.client.get_order_book(symbol='ETHBTC')
        print(depth)

    def place_arbitrage_trade(self):
        # place the arbitrage based on the model's most recent calculations
        # we save time by not updating the values

        # place trade a
        a_side = SIDE_BUY
        if self.pair_a_inversion:
            a_side = SIDE_SELL
        trade_qty = str(
            float(self.pair_a_quote_fill) -
            (float(self.pair_a_quote_fill) % float(self.pair_a_stepSize)))[:7]
        print('placing order for %s %s' % (trade_qty, self.pair_a_valid_name))
        order = self.client.create_order(symbol=self.pair_a_valid_name,
                                         side=a_side,
                                         type=ORDER_TYPE_MARKET,
                                         quantity=trade_qty,
                                         recvWindow=10000)
        print('ORDER: ', order)

        # TODO: receive trade a fill amount

        # place trade b
        b_side = SIDE_BUY
        if self.pair_b_inversion:
            b_side = SIDE_SELL
        trade_qty = str(
            float(self.pair_b_quote_fill) -
            (float(self.pair_b_quote_fill) % float(self.pair_b_stepSize)))[:7]
        print('placing order for %s %s' % (trade_qty, self.pair_b_valid_name))
        order = self.client.create_order(symbol=self.pair_b_valid_name,
                                         side=b_side,
                                         type=ORDER_TYPE_MARKET,
                                         quantity=trade_qty,
                                         recvWindow=10000)
        print('ORDER: ', order)

        # TODO: receive trade b fill amount

        # place trade c
        c_side = SIDE_BUY
        if self.pair_c_inversion:
            c_side = SIDE_SELL
        trade_qty = str(
            float(self.implicit_profit) -
            (float(self.implicit_profit) % float(self.pair_c_stepSize)))[:7]
        print('placing order for %s %s' % (trade_qty, self.pair_c_valid_name))
        order = self.client.create_order(symbol=self.pair_c_valid_name,
                                         side=c_side,
                                         type=ORDER_TYPE_MARKET,
                                         quantity=trade_qty,
                                         recvWindow=10000)
        print('ORDER: ', order)

        # TODO: calculate total trade profit from fill amount

        # print account info after trade
        self.print_account_info()
        return

    def print_account_info(self):
        self.pair_a_valid_name = valid_pair_name[self.pair_a]
        self.pair_b_valid_name = valid_pair_name[self.pair_b]
        self.pair_c_valid_name = valid_pair_name[self.pair_c]

        info = self.client.get_account(recvWindow=10000)
        for balance in info['balances']:
            if balance['asset'] == self.base_asset:
                print(balance['asset'], balance)
                print(balance['free'])
                print('Change %s: %s' %
                      (balance['asset'], float(balance['free']) -
                       float(self.base_asset_account)))
                self.base_asset_account = float(balance['free'])
            elif balance['asset'] == self.quote_asset:
                print(balance['asset'], balance)
                print(balance['free'])
                print('Change %s: %s' %
                      (balance['asset'], float(balance['free']) -
                       float(self.quote_asset_account)))
                self.quote_asset_account = float(balance['free'])
            elif balance['asset'] == self.tertiary_asset:
                print(balance['asset'], balance)
                print('Change %s: %s' %
                      (balance['asset'], float(balance['free']) -
                       float(self.tertiary_asset_account)))
                self.tertiary_asset_account = float(balance['free'])

    def testing_ping(self, total_base_asset):
        # place trades in parallel
        ep = 'https://api.binance.com/api/v1/ping'

        get_request_list = [grequests.get(ep)] * 3

        responses = grequests.map(get_request_list,
                                  exception_handler=self._request_exception,
                                  size=3)

        pair_a_response = responses[0]
        pair_b_response = responses[1]
        pair_c_response = responses[2]

        return

    def update_market_data(self):
        # call this once per second
        response_list = api_lib.get_book_ticker(symbol='all').json()

        # assign the prices to variables
        self.market_data['pair_a_ask'] = self._get_ask_from_json(
            response_list, self.pair_a_valid_name, self.pair_a_inversion)
        self.market_data['pair_b_ask'] = self._get_ask_from_json(
            response_list, self.pair_b_valid_name, self.pair_b_inversion)
        self.market_data['pair_c_ask'] = self._get_ask_from_json(
            response_list, self.pair_c_valid_name, self.pair_c_inversion)

        self.market_data['pair_a_bid'] = self._get_bid_from_json(
            response_list, self.pair_a_valid_name, self.pair_a_inversion)
        self.market_data['pair_b_bid'] = self._get_bid_from_json(
            response_list, self.pair_b_valid_name, self.pair_b_inversion)
        self.market_data['pair_c_bid'] = self._get_bid_from_json(
            response_list, self.pair_c_valid_name, self.pair_c_inversion)

        profit1 = float(self.market_data['pair_a_ask']) * float(
            self.market_data['pair_b_bid'])
        profit2 = float(self.market_data['pair_b_ask']) * float(
            self.market_data['pair_c_bid'])
        profit3 = float(self.market_data['pair_c_ask']) * float(
            self.market_data['pair_a_bid'])

        # arbitrage profit is total after making three trades
        self.market_data[
            'market_arbitrage_profit'] = profit1 * profit2 * profit3

        return self.market_data

    def get_implicit_profit(self, total_base_asset):
        # get the implied profit from executing a triangular arbitrage trade with the specified base asset amount
        # this calculates trades against the most recent order book
        # TODO: implement implicit profit calculation for trading the other direction
        self.update_order_books()

        pair_a_quote_bought = self._get_order_book_quote_value(
            self.pair_a_order_book, total_base_asset, self.pair_a_inversion)
        pair_b_quote_bought = self._get_order_book_quote_value(
            self.pair_b_order_book, pair_a_quote_bought, self.pair_b_inversion)
        base_asset_bought = self._get_order_book_quote_value(
            self.pair_c_order_book, pair_b_quote_bought, self.pair_c_inversion)
        self.implicit_profit = base_asset_bought

        return self.implicit_profit

    def update_order_books(self):
        # update order books in parallel
        # call this sparsely -- when arbitrage_profit is within a specified range
        ep = 'https://api.binance.com/api/v1/depth'
        symbols = [
            self.pair_a_valid_name, self.pair_b_valid_name,
            self.pair_c_valid_name
        ]
        headers = {'X-MBX-APIKEY': os.environ.get('STELLA_API_KEY')}

        get_request_list = []
        for symbol in symbols:
            get_request_list.append(
                grequests.get(ep,
                              params={
                                  'symbol': symbol,
                                  'limit': self.order_book_limit
                              },
                              headers=headers))

        responses = grequests.map(get_request_list,
                                  exception_handler=self._request_exception,
                                  size=3)

        pair_a_response = responses[0]
        pair_b_response = responses[1]
        pair_c_response = responses[2]

        if 429 in [
                pair_a_response.status_code, pair_b_response.status_code,
                pair_c_response.status_code
        ]:
            print('Received a status code 429... exiting')
            exit(1)

        self.pair_a_order_book = pair_a_response.json()
        self.pair_b_order_book = pair_b_response.json()
        self.pair_c_order_book = pair_c_response.json()

        return [
            self.pair_a_order_book, self.pair_b_order_book,
            self.pair_c_order_book
        ]

    @staticmethod
    def _request_exception(request, exception):
        print('Error executing HTTP GET request')
        print("Problem: {}: {}".format(request.url, exception))
        exit(1)

    def _get_order_book_quote_value(self,
                                    order_book,
                                    total_base_asset,
                                    inversion=False):
        # choose the trading direction dependent on inversion factor
        # fees are calculated here
        if inversion:
            profit = self._get_base_amount_from_sell_quote(
                order_book, total_base_asset)
            return profit * (1.0 - self.trade_fee)
        profit = self._get_quote_amount_from_sell_base(order_book,
                                                       total_base_asset)
        return profit * (1.0 - self.trade_fee)

    @staticmethod
    def _get_quote_amount_from_sell_base(order_book, total_base_asset):
        # amount = total_base * price

        base_to_sell = total_base_asset
        quote_bought = 0.0

        for ask in order_book['asks']:
            price = float(ask[0])
            qty = float(ask[1])
            ask_total = price * qty

            if ask_total >= base_to_sell:
                # we can buy all we need within this ask's total
                quote_bought += base_to_sell * price
                base_to_sell -= base_to_sell
                break
            elif base_to_sell > ask_total:
                # we are trying to buy more than this ask total, move on to next ask
                quote_bought += ask_total * price
                base_to_sell -= ask_total

        if base_to_sell > 0.0:
            print(
                'Not enough order book info to calculate trade quantity. Consider increasing the limit parameter.'
            )
        return quote_bought

    @staticmethod
    def _get_base_amount_from_sell_quote(order_book, total_quote_asset):
        # amount = total_base / price

        quote_to_sell = total_quote_asset
        base_bought = 0.0

        for bid in order_book['bids']:
            price = float(bid[0])
            qty = float(bid[1])
            bid_total = price * qty

            if bid_total >= quote_to_sell:
                # we can sell all we need within this bid's total
                base_bought += quote_to_sell * (1.0 / price)
                quote_to_sell -= quote_to_sell
                break
            elif quote_to_sell > bid_total:
                # we are trying to sell more than this bid total, move on to next bid
                base_bought += bid_total * (1.0 / price)
                quote_to_sell -= bid_total

        if quote_to_sell > 0.0:
            print(
                'Not enough order book info to calculate trade quantity. Consider increasing the limit parameter.'
            )
        return base_bought

    @staticmethod
    def _get_ask_from_json(response_list, pair_valid_name, inversion=False):
        for symbol_dict in response_list:
            if symbol_dict['symbol'] == pair_valid_name:
                if inversion:
                    return 1.0 / float(symbol_dict['askPrice'])
                return symbol_dict['askPrice']

    @staticmethod
    def _get_bid_from_json(response_list, pair_valid_name, inversion=False):
        for symbol_dict in response_list:
            if symbol_dict['symbol'] == pair_valid_name:
                if inversion:
                    return 1.0 / float(symbol_dict['bidPrice'])
                return symbol_dict['bidPrice']
client = Client(access_key, secret_key)


def write_log(logline):
    timestamp = datetime.now().strftime("%d/%m %H:%M:%S")
    with open(LOG_FILE_PATH, 'a+') as f:
        f.write(timestamp + ' ' + logline + '\n')


with open('../coins_bought.json', 'r') as f:
    coins = json.load(f)

    for coin in list(coins):
        sell_coin = client.create_order(symbol=coin,
                                        side='SELL',
                                        type='MARKET',
                                        quantity=coins[coin]['volume'])

        BuyPrice = float(coins[coin]['bought_at'])
        LastPrice = float(sell_coin['fills'][0]['price'])
        profit = (LastPrice - BuyPrice) * coins[coin]['volume']
        PriceChange = float((LastPrice - BuyPrice) / BuyPrice * 100)

        if LOG_TRADES:
            timestamp = datetime.now().strftime("%d/%m %H:%M:%S")
            write_log(
                f"Sell: {coins[coin]['volume']} {coin} - {BuyPrice} - {LastPrice} Profit: {profit:.2f} {PriceChange:.2f}%"
            )

os.remove('../coins_bought.json')