Beispiel #1
0
 def __init__(self,
              api_key=None,
              api_secret=None,
              api_passphrase=None,
              ticker_span=100):
     self.api_key = api_key
     self.api_secret = api_secret
     self.api_passphrase = api_passphrase
     self.client = Client(api_key,
                          api_secret,
                          api_passphrase,
                          sandbox=False)
     self.ticker_span = ticker_span  #Number of candlestick data points to acquire
     self.kline_data = []
     self.historical_data = []
     now = int(time.time())
     self.kline_data = np.array(
         self.client.get_kline_data('BTC-USDT', '1min',
                                    (now - self.ticker_span * 60), now))
     self.historical_data = pd.DataFrame(self.kline_data,
                                         columns=[
                                             'TimeStamp', 'Open', 'Close',
                                             'High', 'Low', 'Tx Amount',
                                             'Tx Volume'
                                         ])
     self.candle_stick = self.kline_data[0]  #Most recenr candle stick info
     self.update_indicators()
Beispiel #2
0
 def __init__(self, auth):
     self.api_uri = 'https://openapi-sandbox.kucoin.com'
     self.api_key = auth['api_key']
     self.api_secret = auth['api_secret']
     self.api_passphrase = auth['api_passphrase']
     self.client = Client(self.api_key, self.api_secret,
                          self.api_passphrase)
Beispiel #3
0
def KuCoinBalance():
    print "Connecting To KuCoin..."
    time.sleep(1)
    client = KC_Client(KC_API_KEY, KC_API_SECRET)
    DefaultCoins = ["BTC", "ETH", "KCS", "NEO", "USDT"]
    wallets = {}
    for Wallet in client.get_all_balances():
        # if float(Balance["Total"]):
        if float(Wallet["balance"]) or Wallet["coinType"] in DefaultCoins:
            print "\tRetrieving %s Wallet Data" % Wallet["coinType"]
            wallets.update({
                Wallet["coinType"]: {
                    "Address": "0",
                    "Available": Wallet["balanceStr"],
                    "Symbol": Wallet["coinType"],
                    "Name": Wallet["coinType"],
                    "NativeBalance": "0.0",
                    "NativeCurrency": "USDT",
                    "OnHold": Wallet["freezeBalanceStr"],
                    "TotalAmount": Wallet["balanceStr"]
                }
            })
    wallets.update({"ExchangeName": "KuCoin.com"})
    print
    return wallets
Beispiel #4
0
    def __init__(self, key, secret):
        self.logger = Logger(__name__)

        try:
            self.client = Client(key, secret)
        except Exception as e:
            self.logger.log(e)
            raise ExchangeException(self.__class__.__name__, e)
Beispiel #5
0
    def __init__(self):
        self.disabled = False

        api_key = env_cfg("KUCOIN_KEY")
        api_secret = env_cfg('KUCOIN_SECRET')

        if api_key is None or api_secret is None:
            self.disabled = True
            log.info(
                "Disable KUCOIN because either api_key or api_secret not available"
            )
        else:
            self.client = Client(api_key, api_secret)
            self.cache = ExpiringDict(max_len=200, max_age_seconds=60)
Beispiel #6
0
class Kucoin:
    def __init__(self, key, secret):
        self.logger = Logger(__name__)

        try:
            self.client = Client(key, secret)
        except Exception as e:
            self.logger.log(e)
            raise ExchangeException(self.__class__.__name__, e)

    def getBalances(self):
        try:
            result = self.client.get_all_balances()
            balances = {}

            for currency in result:
                name = currency['coinType'].upper()
                value = float(currency['balance'])

                if value > Config.BALANCE_ZERO:
                    balances[name] = value

            return balances
        except Exception as e:
            self.logger.log(e)
            raise ExchangeException(self.__class__.__name__, e)
Beispiel #7
0
    def __init__(self,
                 api_server: str,
                 api_key: str,
                 secret_key: str,
                 timeout: float,
                 requests_params=None):
        assert (isinstance(api_server, str))
        assert (isinstance(api_key, str))
        assert (isinstance(secret_key, str))
        assert (isinstance(timeout, float))

        self.api_server = api_server
        self.api_key = api_key
        self.secret_key = secret_key
        self.timeout = timeout
        self.client = Client(api_key, secret_key)
Beispiel #8
0
class Trader:
    new_table = False
    SMA_PERIOD = 20
    EMA_PERIOD = 10

    def __init__(self,
                 api_key=None,
                 api_secret=None,
                 api_passphrase=None,
                 ticker_span=100):
        self.api_key = api_key
        self.api_secret = api_secret
        self.api_passphrase = api_passphrase
        self.client = Client(api_key,
                             api_secret,
                             api_passphrase,
                             sandbox=False)
        self.ticker_span = ticker_span  #Number of candlestick data points to acquire
        self.kline_data = []
        self.historical_data = []
        now = int(time.time())
        self.kline_data = np.array(
            self.client.get_kline_data('BTC-USDT', '1min',
                                       (now - self.ticker_span * 60), now))
        self.historical_data = pd.DataFrame(self.kline_data,
                                            columns=[
                                                'TimeStamp', 'Open', 'Close',
                                                'High', 'Low', 'Tx Amount',
                                                'Tx Volume'
                                            ])
        self.candle_stick = self.kline_data[0]  #Most recenr candle stick info
        self.update_indicators()

    def update_indicators(
            self):  #Call this to update the CP, SMA, and EMA arrays
        self.get_cp()
        self.get_sma()
        self.get_ema()
        return self.cp, self.sma, self.ema

    def get_ema(self, period=EMA_PERIOD):
        closing_price = []
        for items in reversed(list(self.historical_data.loc[:, 'Close'])):
            closing_price.append(float(items))  #Gives a list
        var = np.array(closing_price)
        self.ema = np.flip(talib.EMA(var, timeperiod=period)).tolist()

    def get_sma(self, period=SMA_PERIOD):
        closing_price = []
        for items in reversed(list(self.historical_data.loc[:, 'Close'])):
            closing_price.append(float(items))  #Gives a list
        var = np.array(closing_price)
        self.sma = np.flip(talib.SMA(var, timeperiod=period)).tolist()

    def get_cp(self):
        closing_price = []
        for items in reversed(list(self.historical_data.loc[:, 'Close'])):
            closing_price.append(float(items))  #Gives a list
        self.cp = np.flip(closing_price).tolist()
Beispiel #9
0
def Activate_Client():
    global client
    try:
        client = Client(API_KEY, API_SECRET)
        print('Client Activated With API Key [{}].'.format(API_KEY))
    except Exception as Client_Error:
        print('There Was A Client Activation Error Trying Again.')
        Activate_Client()
Beispiel #10
0
def get_historical_klines_tv(symbol, interval, start_str, end_str=None):
    """Get Historical Klines from Kucoin (Trading View)

    See dateparse docs for valid start and end string formats http://dateparser.readthedocs.io/en/latest/

    If using offset strings for dates add "UTC" to date string e.g. "now UTC", "11 hours ago UTC"

    :param symbol: Name of symbol pair e.g BNBBTC
    :type symbol: str
    :param interval: Trading View Kline interval
    :type interval: str
    :param start_str: Start date string in UTC format
    :type start_str: str
    :param end_str: optional - end date string in UTC format
    :type end_str: str

    :return: list of OHLCV values

    """

    # init our array for klines
    klines = []
    client = Client("", "", "")

    # convert our date strings to seconds
    start_ts = date_to_seconds(start_str)

    # if an end time was not passed we need to use now
    if end_str is None:
        end_str = 'now UTC'
    end_ts = date_to_seconds(end_str)

    kline_res = client.get_kline_data(symbol, interval, start_ts, end_ts)

    # print(kline_res)

    # check if we got a result
    if 't' in kline_res and len(kline_res['t']):
        # now convert this array to OHLCV format and add to the array
        for i in range(1, len(kline_res['t'])):
            klines.append(
                (kline_res['t'][i], kline_res['o'][i], kline_res['h'][i],
                 kline_res['l'][i], kline_res['c'][i], kline_res['v'][i]))

    # finally return our converted klines
    return klines
Beispiel #11
0
    def __init__(self, balance_percent_value, coin_name):
        #api_key = '602e39d9a2644e0006e7e2c2'
        #603e5c8473b5c50006582528
        db = DB()

        config = db.connection.all()

        self.api_key = config[0]['api_key']
        #api_secret = '2db4483e-2a76-4c2c-b533-f64a80a25c6d'
        self.api_secret = config[0]['api_secret']
        self.api_passphrase = config[0]['api_pass']
        #, sandbox=True
        self.client = Client(self.api_key, self.api_secret,
                             self.api_passphrase)

        self.base_coin = config[1]['base_coin']
        self.balance_percent = balance_percent_value

        self.pair = coin_name + "-" + self.base_coin
Beispiel #12
0
def display_order_book(pair):
  client = Client("", "", "")

  # get order book
  stdscr = curses.initscr()
  curses.curs_set(0)
  stdscr.addstr(0, 0, str("Pair: " + pair))
  stdscr.addstr(5, 0, "------------------------------------------------")
  stdscr.addstr(6, 0, "Ask Price")
  stdscr.addstr(6, 14, "Ask Size")
  stdscr.addstr(6, 27, "Bid Price")
  stdscr.addstr(6, 40, "Bid Size")
  while True:
    try:
      orderbook = client.get_order_book(pair)
      depth = min(20, (min(len(orderbook["asks"]), len(orderbook["bids"]))))
      ask_prices, ask_sizes, bid_prices, bid_sizes = [], [], [], []
      mid_price = str((float(orderbook["asks"][0][0]) + float(orderbook["bids"][0][0])) / 2.0)
      total_ask_volume = 0.0
      total_bid_volume = 0.0
      spread = float(orderbook["asks"][0][0]) - float(orderbook["bids"][0][0])
      stdscr.addstr(2, 0, "Spread: " + str(spread))
      for i in range(depth):
        total_ask_volume += float(orderbook["asks"][i][1])
        total_bid_volume += float(orderbook["bids"][i][1])
        stdscr.addstr(1, 0, "Mid Price: " + mid_price)
        stdscr.addstr(i+7, 0, str(orderbook["asks"][i][0]))
        stdscr.addstr(i+7, 14, str(orderbook["asks"][i][1]))
        stdscr.addstr(i+7, 27, str(orderbook["bids"][i][0]))
        stdscr.addstr(i+7, 40, str(orderbook["bids"][i][1]))
        stdscr.refresh()
      stdscr.addstr(3, 0, "Ask Volume: " + str(total_ask_volume))
      stdscr.addstr(4, 0, "Bid Volume: " + str(total_bid_volume))
      stdscr.refresh()
      time.sleep(2)
      stdscr.refresh()
    except KeyboardInterrupt:
      curses.curs_set(1)
      curses.endwin()
      break

  curses.curs_set(1)
  curses.endwin()
Beispiel #13
0
class Kucoin:
    def __init__(self):
        self.client = Client(s.KUCOIN_API_KEY, s.KUCOIN_API_SECRET,
                             s.KUCOIN_API_PASSPHRASE)

    def get_ticker(self, symbol):
        _symbol = "-".join(symbol)

        try:
            item = self.client.get_ticker(_symbol)
        except (KucoinAPIException, Exception) as err:
            raise ValueError(str(err))

        try:
            item.update(self.client.get_24hr_stats(_symbol))
        except (KucoinAPIException, Exception) as err:
            raise ValueError(str(err))

        item.update(ticker=symbol[0])
        return item
async def getkuorderbooks():
    exlist = ['GAS/NEO', "GAS/BTC", 'NEO/BTC', 'NEO/USDT', 'NEO/ETH',
              'QTUM/NEO',	'QTUM/BTC', 'LTC/NEO', 'LTC/BTC', 'LTC/ETH']
    client = Client(Key, Secret, language='en_US')
    obs = {}
    for ex in exlist:
        sym = ex.replace("/", "-")
        try:
            obs[ex] = await getorder(client, sym)
        except BaseException as e:
            print("Error in getting %s:%s" % (ex, e))
    return obs
Beispiel #15
0
class KucoinLogic(BaseExchangeBL):
    def __init__(self, account_name='', api_key='', api_secret=''):
        super().__init__("kucoin", account_name, api_key, api_secret)
        self.kucoinClient = KucoinClient(self.api_key, self.api_secret)

    def getSymbolsFromExchange(self):
        data = self.kucoinClient.get_coin_list()
        symbols = set([])
        for item in data:
            if item['coin'] not in symbols:
                symbols.add((item['coin'], self.exchangeName))
        return symbols
Beispiel #16
0
def get_account_assets():

    client = Client(
        os.environ["kucoin_key"],
        os.environ["kucoin_secret"],
        os.environ["kucoin_passphrase"],
    )

    balances = client.get_accounts()

    assets = []
    for balance in balances:
        symbol = balance["currency"]
        amount = float(balance["balance"])
        exchange = "kucoin"

        asset = Asset(symbol=symbol, amount=amount, exchange=exchange)

        if int(amount * 1e18) > 0:
            assets.append(asset)

    return assets
Beispiel #17
0
class KucoinApi:
    def __init__(self, auth):
        self.api_uri = 'https://openapi-sandbox.kucoin.com'
        self.api_key = auth['api_key']
        self.api_secret = auth['api_secret']
        self.api_passphrase = auth['api_passphrase']
        self.client = Client(self.api_key, self.api_secret,
                             self.api_passphrase)

    def get_markets(self):
        markets = self.client.get_markets()
        return markets

    def check_keys(self):
        pass
Beispiel #18
0
class KucoinExchange:
    def __init__(self):
        self.disabled = False

        api_key = env_cfg("KUCOIN_KEY")
        api_secret = env_cfg('KUCOIN_SECRET')

        if api_key is None or api_secret is None:
            self.disabled = True
            log.info(
                "Disable KUCOIN because either api_key or api_secret not available"
            )
        else:
            self.client = Client(api_key, api_secret)
            self.cache = ExpiringDict(max_len=200, max_age_seconds=60)

    def is_disabled(self):
        return self.disabled

    def name(self):
        return self.__class__.__name__

    def get_balances(self):
        if self.disabled:
            raise EnvironmentError("{} is disabled".format(self.name()))

        if self.cache.get('balances'):
            return self.cache.get('balances')

        get_account_response = self.client.get_all_balances()

        balances = [{
            'exchange': 'KUCOIN',
            'currency': b.get('coinType'),
            'available': float(b.get('balance'))
        } for b in get_account_response if float(b.get('balance')) > 0]

        self.cache['balances'] = balances
        return balances
Beispiel #19
0
# manager.py
from kucoin.client import Client
import config
import logging
import sys
import math

log_format = '%(asctime)s:%(levelname)s:%(name)s: %(message)s'
logging.basicConfig(filename='AMPL_manager.log',
                    level=logging.INFO,
                    format=log_format)
client = Client(config.api_key, config.api_secret, config.api_passphrase)


def truncate(number, digits):
    stepper = 10.0**digits
    return math.trunc(stepper * number) / stepper


def place_order(order, stop=None):
    total_value = config.initial_investment * order['multiple']
    price = truncate(total_value / AMPL_total_qty, 4)
    sell_qty = truncate(AMPL_total_qty * order['amount'], 2)
    if stop:
        stop_price = price
    else:
        stop_price = None
    logging.info(
        f'New order: {order["multiple"]}x initial value, {sell_qty:.2f}AMPL @ {price:.2f}USD'
    )
    return client.create_limit_order(symbol=config.market,
Beispiel #20
0
#!/usr/bin/env python
# coding=utf-8

from kucoin.client import Client
from kucoin.exceptions import KucoinAPIException, KucoinRequestException, KucoinResolutionException
import pytest
import requests_mock


client = Client('api_key', 'api_secret')


def test_invalid_json():
    """Test Invalid response Exception"""

    with pytest.raises(KucoinRequestException):
        with requests_mock.mock() as m:
            m.get('https://api.kucoin.com/v1/open/currencies', text='<head></html>')
            client.get_currencies()


def test_api_exception():
    """Test API response Exception"""

    with pytest.raises(KucoinAPIException):
        with requests_mock.mock() as m:
            json_obj = {
                "code": "UNAUTH",
                "msg": "Signature verification failed",
                "success": False,
                "timestamp": 1510287654892
Beispiel #21
0
from datetime import datetime

# ______________________________________________________________________

project_folder = '/home/foxcodenine/Desktop/foxtraders_v1.0'

load_dotenv(os.path.join(project_folder, '.env'), override=True)

# ______________________________________________________________________

api_key = os.getenv('API_KEY')
api_secret = os.getenv('API_SECRET')
api_passphrase = os.getenv('API_PASSPHRASE')

client = Client(api_key, api_secret, api_passphrase)

# ______________________________________________________________________

currencies = client.get_currencies()


def find_crypto(crypto, message):
    crypto = crypto.upper()

    for m in message:
        if m['name'] == crypto:
            pprint.pprint(m)


# find_crypto('BTc', currencies)
Beispiel #22
0
import os.path
import time
import hmac
import hashlib
from decimal import *
try:
    from urllib import urlencode
    from urlparse import urljoin
except ImportError:
    from urllib.parse import urlencode
    from urllib.parse import urljoin

from kucoin.client import Client
kucoin_api_key = 'api_key'
kucoin_api_secret = 'api_secret'
client = Client(api_key='5b35631b09e5a168abec621a',
                api_secret='d564e70a-f45e-49cd-b13c-a31fa5bbbb9d')

args = sys.argv

ticker = args[1]
starttime = datetime.datetime.now(
    datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f%Z")

while (1):
    try:
        filename = ticker.split('-')[0] + "_order_book3.txt"
        filepath = os.path.join('kucoin_data', filename)
        filename1 = ticker.split('-')[0] + "_recentOrders3.txt"
        filepath1 = os.path.join('kucoin_data', filename1)

        print("Kucoin scraper 1.1 aggregating data to ", filename, " and ",
Beispiel #23
0
from kucoin.client import Client
import datetime
import numpy as np


def gravity(bvolume, avolume, bprice, aprice):
    mid_volume = bvolume + avolume
    w1 = bvolume / mid_volume
    w2 = avolume / mid_volume
    return sum([(w1 * aprice), (w2 * bprice)])


client = Client(api_key='5b35631b09e5a168abec621a',
                api_secret='d564e70a-f45e-49cd-b13c-a31fa5bbbb9d')

starttime = datetime.datetime.now(
    datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f%Z")
hist_bestBid, hist_bestAsk, hist_spread, hist_midpoint, hist_volume, hist_midpointVolume, hist_gravity = [], [], [], [], [], [], []
n = 60

while (1):
    time = datetime.datetime.now(
        datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f%Z")
    market_data = client.get_order_book('OMX-BTC', limit=9999)
    recent_orders = client.get_recent_orders('OMX-BTC', limit=9999)
    print(recent_orders)
    break
    buys, sells = market_data['BUY'], market_data['SELL']
    hist_bestBid.append(buys[0][0])
    hist_bestAsk.append(sells[0][0])
    hist_midpoint.append(np.mean([hist_bestAsk[-1], hist_bestBid[-1]]))
    def __init__(self):
        # Output parameters, debug is not useful to normal users
        self.debug = True
        self.verbose = True

        # Modify this according to your personal parameters
        # Keys are top secret, delete them from your account if ever published
        self.simulate = True
        self.play_with_gains = True
        self.api_key = "thereisakeyhere"
        self.secret_key = "thereisakeyherebutitsasecret"
        self.api_client = Client(self.api_key, self.secret_key)
        # Fund rules are the limit you are allowing the bot to trade with, usd estimated with USDT
        self.fund_rules = {
            'BTC': {
                'no_touch_coins': 0,
                'max_coins': 0.01,
                'max_percent': 100
            },
            'ETH': {
                'no_touch_coins': 0,
                'max_coins': 0.1,
                'max_percent': 100
            },
            'NEO': {
                'no_touch_coins': 0,
                'max_coins': 0.5,
                'max_percent': 100
            },
            'USDT': {
                'no_touch_coins': 0,
                'max_coins': 0,
                'max_percent': 100
            },
            'KCS': {
                'no_touch_coins': 0,
                'max_coins': 0,
                'max_percent': 100
            },
            'BCH': {
                'no_touch_coins': 0,
                'max_coins': 0,
                'max_percent': 100
            },
        }
        self.time_limit = {  # Longest time allowed for api calls
            'get_book': 0.4,
            'get_prices': 1
        }
        self.gap_limit_percent = 0.001  # Minimum path earnings default at 0.1%

        # Don't touch this unless you know what you are doing
        self.rate_limits, self.call_count, self.last_timestamp = 1200, 0, 0  # Request limiter per minute, burst distribution
        self.trade_fee = 1 - 0.001  # Deduced from bought asset
        if self.simulate:
            self.balances = {'BTC': 0.1, 'ETH': 1, 'NEO': 0.5}
        else:
            self.balances = {}
        self.liquidations, self.liquidation_limit = [], 0.02  # Max tolerable loss default at 1%, fee not included
        self.tradePrecision, self.pairs, self.gains, self.min_amount, self.path_blacklist = {}, {}, {}, {}, {}
        self.paths, self.order_ids = [], ["", "", "", ""]
        self.last_min_calculation = 0  # Last time the minimum amount for a trade was calculated

        signal.signal(signal.SIGINT, self.exit_program)
        signal.signal(signal.SIGTERM, self.exit_program)
        self.program_running = True
        self.start_engine()
class Bot:
    def __init__(self):
        # Output parameters, debug is not useful to normal users
        self.debug = True
        self.verbose = True

        # Modify this according to your personal parameters
        # Keys are top secret, delete them from your account if ever published
        self.simulate = True
        self.play_with_gains = True
        self.api_key = "thereisakeyhere"
        self.secret_key = "thereisakeyherebutitsasecret"
        self.api_client = Client(self.api_key, self.secret_key)
        # Fund rules are the limit you are allowing the bot to trade with, usd estimated with USDT
        self.fund_rules = {
            'BTC': {
                'no_touch_coins': 0,
                'max_coins': 0.01,
                'max_percent': 100
            },
            'ETH': {
                'no_touch_coins': 0,
                'max_coins': 0.1,
                'max_percent': 100
            },
            'NEO': {
                'no_touch_coins': 0,
                'max_coins': 0.5,
                'max_percent': 100
            },
            'USDT': {
                'no_touch_coins': 0,
                'max_coins': 0,
                'max_percent': 100
            },
            'KCS': {
                'no_touch_coins': 0,
                'max_coins': 0,
                'max_percent': 100
            },
            'BCH': {
                'no_touch_coins': 0,
                'max_coins': 0,
                'max_percent': 100
            },
        }
        self.time_limit = {  # Longest time allowed for api calls
            'get_book': 0.4,
            'get_prices': 1
        }
        self.gap_limit_percent = 0.001  # Minimum path earnings default at 0.1%

        # Don't touch this unless you know what you are doing
        self.rate_limits, self.call_count, self.last_timestamp = 1200, 0, 0  # Request limiter per minute, burst distribution
        self.trade_fee = 1 - 0.001  # Deduced from bought asset
        if self.simulate:
            self.balances = {'BTC': 0.1, 'ETH': 1, 'NEO': 0.5}
        else:
            self.balances = {}
        self.liquidations, self.liquidation_limit = [], 0.02  # Max tolerable loss default at 1%, fee not included
        self.tradePrecision, self.pairs, self.gains, self.min_amount, self.path_blacklist = {}, {}, {}, {}, {}
        self.paths, self.order_ids = [], ["", "", "", ""]
        self.last_min_calculation = 0  # Last time the minimum amount for a trade was calculated

        signal.signal(signal.SIGINT, self.exit_program)
        signal.signal(signal.SIGTERM, self.exit_program)
        self.program_running = True
        self.start_engine()

    def loop(self):
        while self.program_running:
            self.log_debug("Starting new loop")
            # Refresh min amount if necessary
            if time.time() - 600 > self.last_min_calculation:
                self.calculate_min_amount()
            # Refresh blacklist
            self.refresh_blacklist()
            # Get symbols sell price
            success = self.reload_prices()
            if not success:
                continue
            # Calculate path coefficients
            self.log_debug("get_paths_data")
            path_prices = self.get_paths_data()
            self.log_verbose("Found {} potential path".format(
                len(path_prices)))
            self.log_verbose("Gains since started = {}".format(self.gains))

            # Iterate over path in descending values
            for path in sorted(path_prices,
                               key=lambda p: p["path_value"],
                               reverse=True):
                path_value, coin1 = path["path_value"], path["coin1"]
                buy = [None, path["buy1"], path["buy2"], path["buy3"]]
                sym = [None, path["sym1"], path["sym2"], path["sym3"]]
                unique_string = "%.8f%s%s%s" % (path_value, sym[1], sym[2],
                                                sym[3])
                if unique_string in self.path_blacklist:
                    self.log_verbose("Skipping path of the blacklist")
                    continue
                self.log_verbose(
                    "Path val=%.8f;Buy(%r) %s;Buy(%r) %s;Buy(%r) %s" %
                    (path_value, buy[1], sym[1], buy[2], sym[2], buy[3],
                     sym[3]))
                # Get books details and check quantity
                books = [None, [], [], []]
                error, success = False, 0

                # Call order books
                for i in range(1, 4):
                    success, books[i] = self.get_order_book(buy[i], sym[i])
                    if not success or books[i] is None or len(books[i]) < 1:
                        success = False
                        break

                # Skip the rest if an error happened
                if not success:
                    self.log_verbose("Order books could not be retrieved")
                    break
                else:
                    self.log_debug("Received all order books")

                # Calculate optimized quantity and price, factor in fees
                balance = self.balances[coin1]
                order1, order2, order3 = books[1].pop(), books[2].pop(
                ), books[3].pop()
                self.calc_path(balance, order1, order2, order3, path)
                earned, spent = path["earned"], path["spent"]
                # Check if the path is worth walking
                gains = self.apply_precision(earned - spent, coin1)
                min_gains = 0.1**(self.tradePrecision[coin1] - 2)
                if spent <= 0 or earned / spent < 1 + self.gap_limit_percent or gains < min_gains:
                    self.log_verbose(
                        "Path is not profitable anymore : spend %.8f get %.8f"
                        % (spent, earned))
                    self.path_blacklist["%.8f%s%s%s" %
                                        (path_value, sym[1], sym[2],
                                         sym[3])] = time.time()
                    break
                if False and gains < self.tradePrecision[path["coin1"]]:
                    self.log_verbose(
                        "Gains are too small (%.8f), skipping path" % gains)
                    break
                self.log_info("Spending %.8f to earn %.8f : %s >> %s >> %s " %
                              (spent, earned, sym[1], sym[2], sym[3]))

                if not self.simulate:
                    self.program_running = False

                # Everything is okay close the path
                self.order_ids = ["", "", "", ""]
                warm_time = 0.01
                success = self.execute_order(1, path)  # Execute trade 1 A-B
                if success:
                    time.sleep(warm_time)
                    success = self.execute_order(2,
                                                 path)  # Execute trade 2 B-C
                    if success:
                        time.sleep(warm_time)
                        success = self.execute_order(
                            3, path)  # Execute trade 3 C-B
                        if success:
                            # Update available balances and gains
                            if coin1 not in self.gains:
                                self.gains[coin1] = 0
                            self.gains[coin1] = self.apply_precision(
                                self.gains[coin1] + gains, coin1)
                            if self.play_with_gains:
                                self.balances[coin1] = self.apply_precision(
                                    self.balances[coin1] + gains, coin1)
                break

            # Liquidate stuck balances
            self.liquidate()
            # Wait if necessary
            if len(path_prices) < 1:
                self.log_debug("No path found, forced wait of 100ms")
                time.sleep(0.1)
            current_time = time.time()
            loop_wait = self.call_count * (60 / self.rate_limits) - (
                current_time - self.last_timestamp)
            self.call_count = 0
            if loop_wait > 0:
                self.log_verbose("Waiting %.6f seconds before next iteration" %
                                 loop_wait)
                time.sleep(loop_wait)
            self.last_timestamp = current_time
        self.exit_message()

    # SERIOUS BUSINESS, TRIPLE CHECK !
    def execute_order(self,
                      order_num,
                      path,
                      force_price=0,
                      force_qty=0,
                      is_liquidation=False):
        buy, symbol, quantity, price = path["buy%d" % order_num], path[
            "sym%d" % order_num], path["qty%d" % order_num], path["price%d" %
                                                                  order_num]
        order_placed, order_executed, limit_reached, order_canceled = False, False, False, False
        if force_price > 0:
            price = force_price
        if force_qty > 0:
            quantity = force_qty
        if buy:
            deal_type = 'SELL'
        else:
            deal_type = 'BUY'
        if self.simulate:
            while not order_executed and not order_canceled:
                # Place order
                while not order_placed:
                    self.log_verbose(
                        "Trying to place %s order on %s : [Price: %.8f - Quantity: %.8f]"
                        % (deal_type, symbol, price, quantity))
                    try:
                        if buy:
                            self.api_call("create_sell_order")
                            time.sleep(0.05)
                            self.log_verbose("Successfully placed sell order")
                        else:
                            self.api_call("create_buy_order")
                            time.sleep(0.05)
                            self.log_verbose("Successfully placed buy order")
                        order_placed = True
                    except KucoinAPIException as e:  # No use in simulation
                        if e.code is "NO_BALANCE":  # Previous order not or partially filled, only order 2 or 3
                            self.log_verbose(
                                "Previous order not filled, cancel it and liquidate"
                            )
                            if not is_liquidation:
                                self.feed_liquidator(order_num - 1, path)
                        else:
                            self.log_error(
                                "Error while placing %s order. Verifying if order has been placed"
                                % deal_type)
                warm_time = 0.3
                time.sleep(warm_time)

                # Check order status
                if is_liquidation and self.simulate:  # Too shit to calculate
                    return True
                ret, loaded_book = None, False
                while not loaded_book:
                    try:
                        # Load books
                        if buy:
                            self.api_call("get_buy_orders")
                            ret = self.api_client.get_buy_orders(symbol,
                                                                 limit=1)
                        else:
                            self.api_call("get_sell_orders")
                            ret = self.api_client.get_sell_orders(symbol,
                                                                  limit=1)
                        # Check if loaded
                        if ret is not None and len(ret) > 0:
                            loaded_book = True
                        elif not is_liquidation:
                            self.feed_liquidator(order_num, path)
                    except KucoinAPIException as e:
                        self.log_error(
                            "Error during API call : error {} : {}".format(
                                e.status_code, e.response))
                if (buy and ret[0][0] >= price) or (not buy
                                                    and ret[0][0] <= price):
                    self.log_verbose("%s order filled : %.8f %s for %.8f " %
                                     (deal_type, quantity, symbol, price))
                    return True

                # Cancel order
                else:
                    order_canceled = False
                    while not order_canceled:
                        try:
                            self.log_verbose(
                                "Order not executed, trying to cancel")
                            order_canceled = True
                            self.log_verbose("Order canceled")
                        except:
                            self.log_verbose(
                                "Failed to cancel order, trying again")
            if not is_liquidation:
                self.feed_liquidator(order_num, path)
            return False

        # WARNING : Not a simulation anymore! Real money to be lost
        # Real money : cancel order to check execution, check dealt orders for remaining money, liquidate remaining
        else:
            # Place order
            while not order_placed:
                self.log_verbose(
                    "Trying to place %s order on %s : [Price: %.8f - Quantity: %.8f]"
                    % (deal_type, symbol, price, quantity))
                try:
                    if buy:
                        self.api_call("create_sell_order")
                    else:
                        self.api_call("create_buy_order")
                    ret = self.api_client.create_order(symbol=symbol,
                                                       order_type=deal_type,
                                                       price="%.8f" % price,
                                                       amount="%.8f" %
                                                       quantity)
                    self.order_ids[order_num] = ret["orderOid"]
                    self.log_verbose("Successfully placed order")
                    order_placed = True
                except KucoinAPIException as e:
                    if e.code == "NO_BALANCE":  # Previous order not or partially filled, only order 2 or 3
                        self.log_verbose(
                            "No balance, previous order may not be filled yet, checking"
                        )
                        if not is_liquidation:
                            # Check and cancel + liquidate previous order if necessary
                            success = self.check_order(order_num - 1, path)
                            if not success:
                                return False
                            self.log_verbose(
                                "No problem with the previous order, continuing"
                            )
                            order_placed = True
                    else:
                        self.log_error(
                            "Error during API call : error {} : code {} : {}".
                            format(e.status_code, e.code, e.response))
                        self.log_error(
                            "Exception while placing %s order. Stop EVERYTHING"
                            % deal_type)
                        self.program_running = False
                        return False

            # Check if order has been dealt
            success = self.check_order(order_num, path)
            return success

    def check_order(self, order_num, path):
        buy = path["buy%d" % order_num]
        symbol = path["sym%d" % order_num]
        quantity = path["qty%d" % order_num]
        price = path["price%d" % order_num]
        spent, earned = path["spent"], path["earned"]
        if buy:
            deal_type = 'SELL'
            precision_coin = path["coin%d" % order_num]
        else:
            deal_type = 'BUY'
            precision_coin = path["coin%d" % ((order_num % 3) + 1)]
        oid = self.order_ids[order_num]
        check_cancel = True

        # Check order execution
        order_failed, book_is_valid = False, True
        while not order_failed:
            time.sleep(0.020)
            try:
                self.api_call("get_dealt_orders")
                ret = self.api_client.get_symbol_dealt_orders(
                    symbol=symbol, order_type=deal_type, limit=20)
            except KucoinAPIException as e:
                self.log_error("Error {}: {}".format(e.status_code,
                                                     e.response))
                time.sleep(0.05)  # Limit spam if failure
            # Check if order active
            dealt_amount = 0
            for order in ret["datas"]:
                if order["orderOid"] == oid:
                    dealt_amount = dealt_amount + order["amount"]
            # Check the book
            ret = None
            filled_rate = 100 * dealt_amount / quantity
            self.log_debug("Completed %.1f percent of order" % filled_rate)
            if filled_rate > 99.9:
                self.log_debug(
                    "Dealt threshold reached, order successfully executed")
                return True
            else:
                if book_is_valid:
                    # Load order book
                    try:
                        if deal_type == "SELL":
                            self.api_call("get_buy_orders")
                            ret = self.api_client.get_buy_orders(symbol,
                                                                 limit=1)
                        else:
                            self.api_call("get_sell_orders")
                            ret = self.api_client.get_sell_orders(symbol,
                                                                  limit=1)
                        if ret and len(ret) > 0:
                            book_line = ret.pop()
                            if not ((deal_type == "SELL"
                                     and book_line[0] >= price) or
                                    (deal_type == "BUY"
                                     and book_line[0] <= price)):
                                self.log_debug(
                                    "No more order in the book to close")
                                book_is_valid = False
                        else:
                            self.log_debug("The book contains nothing")
                            book_is_valid = False
                    except KucoinAPIException as e:
                        self.log_error("Error {}: {}".format(
                            e.status_code, e.response))
                else:
                    order_failed = True

        # Try to cancel, if order is dealt it will not work
        while check_cancel:
            try:
                self.api_call("cancel_order")
                self.api_client.cancel_order(order_id=oid,
                                             order_type=deal_type)
                self.log_verbose(
                    "Order %d not dealt or partially, cancelled." % order_num)
                check_cancel = False
            except KucoinAPIException as e:
                if e.status_code != 404:
                    self.log_error("Error {}: {}".format(
                        e.status_code, e.response))
                    time.sleep(0.1)  # Limit spam if failure
                else:
                    self.log_verbose(
                        "Order not found, already dealt or never created")
                    return True  # Order can't be cancelled, it has been dealt

        # Handle failure
        # Fetch dealt orders
        loaded_orders = False
        ret = None
        while not loaded_orders:
            try:
                self.api_call("get_symbol_dealt_orders")
                ret = self.api_client.get_symbol_dealt_orders(
                    symbol=symbol, order_type=deal_type, limit=20)
                loaded_orders = True
            except KucoinAPIException as e:
                self.log_error("Error {}: {}".format(e.status_code,
                                                     e.response))
                time.sleep(0.1)
        # Get dealt balance for order
        dealt_amount = 0
        for deal in ret["datas"]:
            dealt_amount = self.apply_precision(dealt_amount + deal["amount"],
                                                precision_coin)
        spent_amount = self.apply_precision(
            dealt_amount * (2 - self.trade_fee), precision_coin)
        remaining = self.apply_precision("qty%d" % order_num - spent_amount,
                                         precision_coin)
        self.log_verbose(
            "Cancelled order detail : %.8f dealt; %.8f remaining" %
            (dealt_amount, remaining))

        # Refactor the path to match the quantities
        new_spent = self.apply_precision(spent * remaining / quantity,
                                         path["coin1"])
        new_earned = self.apply_precision(earned * remaining / quantity,
                                          path["coin1"])
        path["spent"], path["earned"] = new_spent, new_earned
        path["qty%d" % order_num] = remaining

        # Create new path if order 1 or 2 partially dealt
        if order_num != 3 and dealt_amount > 0:
            if buy:
                new_precision = path["coin%d" % (order_num + 1)]
            else:
                new_precision = path["coin%d" % (((order_num + 1) % 3) + 1)]
            artificial_spent = self.apply_precision(
                spent * dealt_amount / quantity, path["coin1"])
            artificial_earned = self.apply_precision(
                earned * dealt_amount / quantity, path["coin1"])
            new_qty = self.apply_precision(
                path["qty%d" % order_num + 1] * dealt_amount / quantity,
                path[new_precision])
            if new_qty > self.min_amount[new_precision]:
                # Create a new path only for liquidation
                artificial_path = dict(path_value=path["path_value"],
                                       coin1=path["coin1"],
                                       coin2=path["coin2"],
                                       coin3=path["coin3"],
                                       buy1=path["buy1"],
                                       buy2=path["buy2"],
                                       buy3=path["buy3"],
                                       sym1=path["sym1"],
                                       sym2=path["sym2"],
                                       sym3=path["sym3"],
                                       spent=artificial_spent,
                                       earned=artificial_earned,
                                       qty1=path["qty1"],
                                       qty2=path["qty2"],
                                       qty3=path["qty3"],
                                       price1=path["price1"],
                                       price2=path["price2"],
                                       price3=path["price3"])
                # Mod quantity
                artificial_path["qty%d" % order_num + 1] = new_qty
                self.feed_liquidator(order_num + 1, artificial_path)

        if order_num != 1:
            # Add to liquidation if it failed
            if remaining > self.min_amount[precision_coin]:
                self.log_verbose(
                    "Order %d failed, add to liquidation : Qty %.8f; Price %.8f; Sym %s; Buy%s"
                    %
                    (order_num, path["qty%d" % order_num], price, symbol, buy))
                self.feed_liquidator(order_num, path)
            else:
                self.log_verbose(
                    "Insufficient quantity remaining, no need to liquidate %s"
                    % precision_coin)
        else:
            self.log_verbose("Order %d failed, no need to liquidate %s" %
                             (order_num, path["coin1"]))
        return False

    def feed_liquidator(self, order_num, path, force_down=False):
        if order_num is 1:
            return
        coin1, spent = path["coin1"], path["spent"]
        buy, symbol, quantity, price = path["buy%d" % order_num], path[
            "sym%d" % order_num], path["qty%d" % order_num], path["price%d" %
                                                                  order_num]
        self.log_verbose(
            "Order %d failed, add to liquidation : Qty %.8f; Price %.8f; Sym %s; Buy%s"
            % (order_num, quantity, price, symbol, buy))
        self.liquidations.append({
            "force_down": force_down,
            "failed_sym": symbol,
            "max_loss": self.liquidation_limit,
            "spent": spent,
            "path": path
        })
        # Update available balances and gains
        if coin1 not in self.gains:
            self.gains[coin1] = 0
        self.balances[coin1] = self.apply_precision(
            self.balances[coin1] - spent, coin1)
        self.gains[coin1] = self.apply_precision(self.gains[coin1] - spent,
                                                 coin1)

    def liquidate(self):
        if not self.simulate:
            return
        liquidated = []
        list_len, index = len(self.liquidations), 0
        while index < list_len:
            entry = self.liquidations[index]
            index = index + 1

            # Define the coins to deal with
            force_down, path, spent, max_loss, failed_sym = entry[
                "force_down"], entry["path"], entry["spent"], entry[
                    "max_loss"], entry["failed_sym"]
            earned = path["earned"]
            if failed_sym is path[
                    "sym2"]:  # Try trade up first then down if not profitable
                order_num = 2
                if force_down:  # Trade down
                    coin, coin1 = path["coin2"], path["coin3"]
                    buy = path["buy2"]
                    qty = path["qty2"]
                    if buy:
                        price = path["price2"] * spent / earned
                    else:
                        price = path["price2"] * earned / spent
                else:  # Trade up, default
                    coin, coin1 = path["coin2"], path["coin1"]
                    buy = not path["buy1"]
                    qty = self.apply_precision(path["qty1"] * self.trade_fee,
                                               coin1)
                    price = path["price1"]
            else:  # Trade down
                order_num = 3
                coin, coin1 = path["coin3"], path["coin1"]
                buy = path["buy3"]
                qty = path["qty3"]
                if buy:
                    price = path["price3"] * spent / earned
                else:
                    price = path["price3"] * earned / spent
            self.log_debug(
                "Initial values : price %.8f; qty %.8f; spent %.8f" %
                (price, qty, spent))

            # Define the symbol
            if coin in self.pairs and coin1 in self.pairs[coin]:
                symbol = self.pairs[coin][coin1]["symbol"]
            else:
                symbol = self.pairs[coin1][coin]["symbol"]

            self.log_debug("Trying to liquidate %s on symbol %s" %
                           (coin, symbol))
            # Get books for coin to coin1
            success, book = self.get_order_book(buy, symbol, limit=25)
            if not success or book is None or len(book) < 1:
                self.log_error("Error during api call for liquidation of %s" %
                               coin)
                continue

            # Check if prices and quantity

            if buy:
                book.sort(key=lambda order: order[0], reverse=True)
                limit_price, max_qty = book[0][0], book[0][1]
                book.pop()
                while max_qty < qty and len(
                        book
                ) > 0:  # Consume orders until qty and price are good
                    order = book.pop()
                    limit_price = order[0]
                    max_qty = max_qty + order[1]
                self.log_debug(
                    "Calculated : qty %.8f; max_qty %.8f; price %.8f; limit_price %.8f"
                    % (qty, max_qty, price, limit_price))
                if max_qty < qty or limit_price < price * (1 - max_loss):
                    if failed_sym is path["sym2"]:
                        self.log_verbose(
                            "Order 2 liquidation failed, changing trade order")
                        entry["force_down"] = not force_down
                    self.log_verbose(
                        "Couldn't liquidate sell, buy price is too low : %.8f at quantity %.8f"
                        % (limit_price, max_qty))
                    continue  # Too low to sell back
            else:
                book.sort(key=lambda order: order[0])
                limit_price, max_qty = book[0][0], book[0][1]
                book.pop()
                min_qty = qty * (1 - max_loss)
                max_price = price * (qty / min_qty)
                while max_qty < min_qty and len(
                        book
                ) > 0:  # Consume orders until qty and price are good
                    order = book.pop()
                    limit_price = order[0]
                    max_qty = max_qty + order[1]
                self.log_debug(
                    "Calculated : min_qty %.8f; max_qty %.8f; max_price %.8f; limit_price %.8f; price %.8f"
                    % (min_qty, max_qty, max_price, limit_price, price))
                if max_qty < min_qty or limit_price > max_price:
                    if failed_sym is path["sym2"]:
                        entry["force_down"] = not force_down
                    self.log_verbose(
                        "Couldn't liquidate buy, sell price is too high : %.8f at quantity %.8f"
                        % (limit_price, min_qty))
                    continue  # Too expensive to buy back
                dust_qty = 0
                leftover_balance = (price * qty) - (min_qty * limit_price)
                if leftover_balance > 0:
                    dust_qty = leftover_balance / limit_price
                self.log_debug(
                    "dust_qty %.8f;leftover %.8f;qty %.8f; price %.8f;min_qty %.8f;limit_price %.8f"
                    % (dust_qty, leftover_balance, qty, price, min_qty,
                       limit_price))
                qty = self.apply_precision(min_qty + dust_qty, coin)

            # Execute order
            success = self.execute_order(order_num,
                                         path,
                                         force_price=limit_price,
                                         force_qty=qty,
                                         is_liquidation=True)
            if not success:
                self.log_error(
                    "Error during order execution for liquidation of %s" %
                    coin)
            else:
                self.log_verbose("Successfully liquidated %.8f %s for %.8f" %
                                 (qty, symbol, limit_price))
                liquidated.append(index - 1)
                if failed_sym is path[
                        "sym2"] and force_down:  # Add the third step to liquidation
                    path["earned"] = path["spent"]
                    if buy:
                        overspend_ratio = price / limit_price
                        path["qty3"] = self.apply_precision(
                            path["qty3"] / overspend_ratio, path["coin3"])
                    else:
                        overspend_ratio = path["qty2"] / qty
                        path["qty3"] = self.apply_precision(
                            path["qty3"] / overspend_ratio, path["coin1"])
                    new_max_loss = max_loss - (overspend_ratio - 1)
                    self.liquidations.append({
                        "force_down": False,
                        "failed_sym": path["sym3"],
                        "max_loss": new_max_loss,
                        "spent": spent,
                        "path": path
                    })
                    list_len = list_len + 1
                else:
                    if buy:
                        total = qty * limit_price * self.trade_fee
                    else:
                        total = qty * self.trade_fee
                    self.balances[coin1] = self.apply_precision(
                        self.balances[coin1] + total, coin1)
                    self.gains[coin1] = self.apply_precision(
                        self.gains[coin1] + total, coin1)

        for index in list(reversed(liquidated)):  # Remove solved liquidations
            self.log_debug("Removing liquidation entry : {}".format(
                self.liquidations[index]))
            del self.liquidations[index]

    def refresh_blacklist(self):
        for unique_string in list(self.path_blacklist.keys()):
            if self.path_blacklist[unique_string] < time.time() - 10:
                self.log_debug("Remove path from blacklist : %s" %
                               unique_string)
                del self.path_blacklist[unique_string]

    def get_order_book(self, buy, sym, limit=1):
        self.api_call("get_buy/sell_orders")
        start_get_book = time.time()
        book, success = [], False
        # Call the book
        try:
            if buy:
                book = self.api_client.get_buy_orders(sym, limit=limit)
            else:
                book = self.api_client.get_sell_orders(sym, limit=limit)
            success = True
        except:
            success = False
            self.log_error("Failed to load the order book for %s" % sym)
        # Handle max allowed time
        if time.time() - start_get_book > self.time_limit['get_book']:
            success = False
            self.log_verbose("Book request took too long")
        return success, book

    def calc_path(self, balance1, order1, order2, order3,
                  path):  # Data format : {balance, book1, book2, book3}
        self.log_debug("Calculating path prices and quantity")
        coin1, coin2, coin3 = path["coin1"], path["coin2"], path["coin3"]
        buy1, buy2, buy3 = path["buy1"], path["buy2"], path["buy3"]
        # Down the path
        # Hop 1
        if buy1:
            balance1 = self.apply_precision(balance1, coin1)
            qty = min(order1[1], balance1)  # Max I can sell
            balance2 = (qty * order1[0]) * self.trade_fee
        else:
            max_price = (order1[0] * order1[1])
            order_buy_price = min(max_price, balance1)  # Max I can spend
            balance2 = (order_buy_price / order1[0]) * self.trade_fee
        balance2 = self.apply_precision(balance2, coin2)
        self.log_debug("Down path : balance %.8f; Order %r; isBuy %s" %
                       (balance1, order1, buy1))
        # Hop 2
        if buy2:
            qty = min(order2[1], balance2)  # Max I can sell
            balance3 = (qty * order2[0]) * self.trade_fee
        else:
            max_price = (order2[0] * order2[1])
            order_buy_price = min(max_price, balance2)  # Max I can spend
            balance3 = (order_buy_price / order2[0]) * self.trade_fee
        balance3 = self.apply_precision(balance3, coin3)
        self.log_debug("Down path : balance %.8f; Order %r; isBuy %s" %
                       (balance2, order2, buy2))
        # Hop 3
        if buy3:
            qty = min(order3[1], balance3)  # Max I can sell
            earned = (qty * order3[0]) * self.trade_fee
        else:
            max_price = (order3[0] * order3[1])
            order_buy_price = min(max_price, balance3)  # Max I can spend
            earned = (order_buy_price / order3[0]) * self.trade_fee
        earned = self.apply_precision(earned, coin1)
        self.log_debug("Down path : balance %.8f; Order %r; isBuy %s" %
                       (balance3, order3, buy3))
        self.log_debug("Down path final balance : %.8f" % earned)

        # Up the path
        balance1, balance2, balance3 = earned, 0, 0
        # Hop 3
        if buy3:
            qty3 = self.apply_precision(
                (balance1 / self.trade_fee) / order3[0], coin3)  # Qty sold
            balance3 = qty3
        else:
            qty3 = self.apply_precision(balance1 / self.trade_fee,
                                        coin1)  # Qty bought
            balance3 = qty3 * order3[0]
            balance3 = self.apply_precision(balance3, coin3)
        self.log_debug("Up path : balance %.8f; Order %r; isBuy %s" %
                       (balance1, order3, buy3))
        # Hop 2
        if buy2:
            qty2 = self.apply_precision(
                (balance3 / self.trade_fee) / order2[0], coin2)  # Qty sold
            balance2 = qty2
        else:
            qty2 = self.apply_precision(balance3 / self.trade_fee,
                                        coin3)  # Qty bought
            balance2 = qty2 * order2[0]
            balance2 = self.apply_precision(balance2, coin2)
        self.log_debug("Up path : balance %.8f; Order %r; isBuy %s" %
                       (balance3, order2, buy2))
        # Hop 1
        if buy1:
            qty1 = self.apply_precision(
                (balance2 / self.trade_fee) / order1[0], coin1)  # Qty sold
            spent = qty1
        else:
            qty1 = self.apply_precision(balance2 / self.trade_fee,
                                        coin2)  # Qty bought
            spent = qty1 * order1[0]
            spent = self.apply_precision(spent, coin1)
        self.log_debug("Up path : balance %.8f; Order %r; isBuy %s" %
                       (balance2, order1, buy1))
        self.log_debug("Up path final balance is %.8f" % spent)

        # Down the path again, adjusting precision
        self.log_debug("Adjusting precision and values")
        balance1, balance2, balance3 = spent, 0, 0
        # Hop 1
        if buy1:
            qty1 = balance1  # Max I can sell
            balance2 = (qty1 * order1[0]) * self.trade_fee
        else:
            qty1 = self.apply_precision(balance1 / order1[0], coin2)
            balance2 = qty1 * self.trade_fee
        balance2 = self.apply_precision(balance2, coin2)
        self.log_debug("Down path : balance %.8f; Order %r; isBuy %s" %
                       (balance1, order1, buy1))
        # Hop 2
        if buy2:
            qty2 = balance2  # Max I can sell
            balance3 = (qty2 * order2[0]) * self.trade_fee
        else:
            qty2 = self.apply_precision(balance2 / order2[0], coin3)
            balance3 = qty2 * self.trade_fee
        balance3 = self.apply_precision(balance3, coin3)
        self.log_debug("Down path : balance %.8f; Order %r; isBuy %s" %
                       (balance2, order2, buy2))
        # Hop 3
        if buy3:
            qty3 = balance3  # Max I can sell
            earned = (qty3 * order3[0]) * self.trade_fee
        else:
            qty3 = self.apply_precision(balance3 / order3[0], coin1)
            earned = qty3 * self.trade_fee
        earned = self.apply_precision(earned, coin1)
        self.log_debug("Down path : balance %.8f; Order %r; isBuy %s" %
                       (balance3, order3, buy3))
        self.log_debug("Down path final balance : %.8f" % earned)

        path["qty1"], path["qty2"], path["qty3"] = qty1, qty2, qty3
        path["price1"], path["price2"], path["price3"] = order1[0], order2[
            0], order3[0]
        path["spent"], path["earned"] = spent, earned

    def get_paths_data(self):
        path_prices = []
        trade_fee = self.trade_fee**3
        pairs = self.pairs
        for path in self.paths:
            p0, p1, p2 = path[0], path[1], path[2]
            if p0 in self.balances and self.balances[p0] > 0:
                path_value, buy1, buy2, buy3 = 1, False, False, False
                # First hop
                if path[1] in pairs[p0]:
                    if pairs[p0][path[1]]["sell"] <= 0:
                        continue
                    path_value = path_value / pairs[p0][p1]["sell"]
                    sym1 = "%s-%s" % (p1, p0)
                else:
                    path_value = path_value * pairs[p1][p0]["buy"]
                    sym1 = "%s-%s" % (p0, p1)
                    buy1 = True
                # Second hop
                if path[1] in pairs and p2 in pairs[p1]:
                    if pairs[p1][p2]["sell"] <= 0:
                        continue
                    path_value = path_value / pairs[p1][p2]["sell"]
                    sym2 = "%s-%s" % (p2, p1)
                else:
                    path_value = path_value * pairs[p2][p1]["buy"]
                    sym2 = "%s-%s" % (p1, p2)
                    buy2 = True
                # Third hop
                if p2 in pairs and p0 in pairs[p2]:
                    if pairs[p2][p0]["sell"] <= 0:
                        continue
                    path_value = path_value / pairs[p2][p0]["sell"]
                    sym3 = "%s-%s" % (p0, p2)
                else:
                    path_value = path_value * pairs[p0][p2]["buy"]
                    sym3 = "%s-%s" % (p2, p0)
                    buy3 = True
                path_value = path_value * trade_fee
                if path_value - self.gap_limit_percent > 1:
                    path_prices.append({
                        "path_value": path_value,
                        "coin1": p0,
                        "coin2": p1,
                        "coin3": p2,
                        "buy1": buy1,
                        "buy2": buy2,
                        "buy3": buy3,
                        "sym1": sym1,
                        "sym2": sym2,
                        "sym3": sym3
                    })
        self.log_debug(path_prices)
        return path_prices

    def apply_precision(self, amount, coin):
        return float(
            format(amount - (0.1**self.tradePrecision[coin]),
                   '.%df' % self.tradePrecision[coin]))

    def reload_prices(self):
        self.log_debug("reload_prices")
        start_get_prices = time.time()
        req = None
        try:
            self.api_call("get_trading_symbols")
            req = self.api_client.get_trading_symbols()
            success = True
            if time.time() - start_get_prices > self.time_limit[
                    'get_prices']:  # Error if call too long
                success = False
        except KucoinAPIException as e:
            print("Error during request : error {} : {} ".format(
                e.status_code, e.message))
            success = False
        if success:
            pairs = self.pairs
            # prices = self.prices
            for symbol in req:
                coin_type, coin_type_pair, sell, buy = symbol[
                    "coinType"], symbol["coinTypePair"], symbol.get(
                        "sell", 0), symbol.get("buy", 0)
                if coin_type_pair in pairs and coin_type in pairs[
                        coin_type_pair]:
                    if sell is None:
                        sell = 0
                    if buy is None:
                        buy = 0
                    if buy == 0 or 1 - sell / buy >= 0.03:
                        sell, buy = 0, 0
                    pairs[coin_type_pair][coin_type]["sell"] = sell
                    pairs[coin_type_pair][coin_type]["buy"] = buy
            self.log_debug(pairs)
        return success

    def calculate_min_amount(self):
        self.reload_prices()
        margin = 1.1
        usd_btc = self.pairs['USDT']['BTC']['sell']
        for coinType in self.pairs['BTC']:
            usd_price = self.pairs['BTC'][coinType]['sell'] * usd_btc * margin
            if usd_price == 0:
                usd_price = 1000000  # No data, play it safe
            self.min_amount['coinType'] = 1 / math.log10(usd_price)
        self.min_amount['BTC'] = 1 / math.log10(usd_btc * margin)
        self.last_min_calculation = time.time()

    def start_engine(self):
        # Load list of pairs
        self.get_pairs_list()
        # Get list of coins
        self.get_coins_info()
        # Load funds available for trading based on balances, rules and volume
        self.get_avail_funds()
        self.log_info("Funds available for trading are : {}".format(
            self.balances))
        # load prices
        self.calculate_min_amount()
        # Start analysis & trade loop
        self.loop()

    def get_pairs_list(self):
        try:
            self.api_call("get_trading_symbols")
            req = self.api_client.get_trading_symbols()
        except KucoinAPIException as e:
            print("Error during request : error {} : {} ".format(
                e.status_code, e.message))
            self.get_pairs_list()
            return
        # Add all pairs to the list
        for pair in req:
            if pair["trading"]:
                if pair["coinTypePair"] not in self.pairs:
                    self.pairs[pair["coinTypePair"]] = {}
                # self.prices["{}-{}".format(pair["coinType"], pair["coinTypePair"])] = { "buy": 0, "sell": 0 }
                self.pairs[pair["coinTypePair"]][pair["coinType"]] = {
                    "buy": 0,
                    "sell": 0,
                    "symbol": pair["symbol"]
                }
        # Remove symbol with only one pair
        for QC1 in list(self.pairs.keys()):
            count = 0
            coin = QC1
            for AC1 in list(self.pairs[QC1].keys()):
                coin = AC1
                if AC1 in self.pairs:  # AC1 is a quote coin
                    for QC2 in list(self.pairs[AC1].keys()):
                        if QC2 in self.pairs[QC1] or (QC2 in self.pairs and QC1
                                                      in self.pairs[QC2]):
                            self.paths.append([QC1, AC1, QC2])
                            count = count + 1
                else:  # AC1 is not a quote coin
                    for QC2 in list(self.pairs.keys()):
                        if AC1 in self.pairs[QC2].keys():
                            if QC1 != QC2:
                                if QC1 in self.pairs[QC2] or QC2 in self.pairs[
                                        QC1]:
                                    self.paths.append([QC1, AC1, QC2])
                                    count = count + 1
            if count == 0:
                del (self.pairs[QC1][coin])
        # Count pairs
        pairs_count = 0
        for QC1 in self.pairs.keys():
            pairs_count = pairs_count + len(self.pairs[QC1])
        self.log_debug("All tradable pairs ({}) are : \n{}".format(
            pairs_count, self.pairs))

    def get_coins_info(self):
        try:
            self.api_call("get_coin_list")
            coins = self.api_client.get_coin_list()
            for coin in coins:
                self.tradePrecision[coin["coin"]] = coin["tradePrecision"]
        except KucoinAPIException as e:
            print("Error during request : error {} : {} ".format(
                e.status_code, e.message))
            self.get_coins_info()
            return

    def get_avail_funds(self):  # No real money for now
        # Get account balance
        try:
            self.api_call("get_all_balances")
            all_balances = self.api_client.get_all_balances()
        except KucoinAPIException as e:
            print("Error during request : error {} : {} ".format(
                e.status_code, e.message))
            self.get_avail_funds()
            return
        for coin in all_balances:
            free_balance = coin["balance"]
            if free_balance > 0:
                self.balances[coin["coinType"]] = free_balance
        self.log_debug("All balances in account : {}".format(self.balances))

        # Apply manual rules
        for symbol in list(self.balances.keys()):
            # Remove
            if symbol not in self.fund_rules:
                del (self.balances[symbol])
                continue
            initial_balance = self.balances[symbol]
            # Remove no touch coins from balance
            if self.balances[symbol] > self.fund_rules[symbol][
                    'no_touch_coins']:
                self.balances[symbol] = self.balances[
                    symbol] - self.fund_rules[symbol]['no_touch_coins']
            else:
                del (self.balances[symbol])
            # limit the available balance to the max percentage allowed
            percent_limit = initial_balance * self.fund_rules[symbol][
                'max_percent'] / 100
            if self.balances[symbol] > percent_limit:
                self.balances[symbol] = percent_limit
                self.log_verbose("{} limited to {}% of total : {}".format(
                    symbol, self.fund_rules[symbol]["max_percent"],
                    "%.2f" % self.balances[symbol]))
            # limit to the max of coins allowed
            if self.balances[symbol] > self.fund_rules[symbol]['max_coins']:
                self.balances[symbol] = self.fund_rules[symbol]['max_coins']
                self.log_verbose(
                    "{} balance exceed max_coins rule, limiting to {}{}".
                    format(symbol, self.balances[symbol], symbol))

    def api_call(self, command):
        self.call_count = self.call_count + 1
        if self.call_count > 200:
            sys.exit()
        self.log_debug("API call : {} , counter: {}".format(
            command, self.call_count))

    def exit_message(self):
        self.log_info("Program interrupted, session stats :")
        self.log_info("Gains : \n{}".format(self.gains))
        self.log_verbose("Pending liquidations : \n{}".format(
            self.liquidations))
        self.log_verbose(
            "Final trading balance (Depends on balance rules) : \n{}\n".format(
                self.balances))

    def exit_program(self, signum, frame):
        self.log_info("Interrupt signal received : SIG %d" % signum)
        self.program_running = False

    @staticmethod
    def log_error(*text):
        print('%.6f [ERR]' % time.time(), *text)

    @staticmethod
    def log_info(*text):
        print('%.6f [INF]' % time.time(), *text)

    def log_debug(self, *text):
        if self.debug:
            print('%.6f [DBG]' % time.time(), *text)

    def log_verbose(self, *text):
        if self.verbose:
            print('%.6f [VRB]' % time.time(), *text)
import pandas as pd
import ta
import datetime
import math
import numpy as np
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import dash_core_components as dcc
import dash_html_components as html
import dash
from dash.dependencies import Input, Output

#initiates Kucoin account
from kucoin.client import Client
client = Client("CLIENTKEY", "SECRETKEY", "PASSPHRASE")

#GMail Credentials
MY_ADDRESS = ''
PASSWORD = ''
s = smtplib.SMTP(host='smtp.gmail.com', port=587)
s.starttls()
s.login(MY_ADDRESS, PASSWORD)

#initiates emails
msg = MIMEMultipart()
msg['From'] = MY_ADDRESS
msg['To'] = MY_ADDRESS
msg['Subject'] = "KuCoin Trading Bot"
#exception module
from kucoin.exceptions import KucoinAPIException
binance_gas_add = "AexzA2PoEytX3nKwTpx4fgXovFPhUzydxb"
poloniex_btc_add = "1KGFzwUrLtQc8GfmWT8NRV4XfikbYKFqZh"
kucion_btc_add = "14eg4a5q1tucRcBipC8aD5tS4a5i9gb5hv"
binance_btc_add = "14eg4a5q1tucRcBipC8aD5tS4a5i9gb5hv"

poloniex_bitcoin_withdrawl_fee = 0.0005
binance_bitcoin_withdrawl_fee = 0.001
kucoin_bitcoin_withdrawl_fee = 0.0005

binance_trading_fee = 0.001
kucoin_trading_fee = 0.001
poloniex_trading_fee = 0.0015

binance_client = BinanceClient(binance_api_key, binance_api_secret)
poloniex_client = poloniex.Poloniex(poloniex_api_key, poloniex_api_secret)
kucion_client = KucoinClient(kucoin_api_key, kucoin_api_secret)

fixes = [{
    'coinmarketcap': 'MIOTA',
    'binance': 'IOTA'
}, {
    'coinmarketcap': 'BCH',
    'binance': 'BCC'
}]

max_principal_btc = 0.1


def main():
    while True:
        df = pd.read_csv("gas-btc.csv")
async def parser(message):
    config.read('config.ini')
    binance_key = config['Binance']['binance_key']
    binance_sec = config['Binance']['binance_sec']
    kucoin_key = config['Kucoin']['kucoin_key']
    kucoin_sec = config['Kucoin']['kucoin_sec']
    kucoin_api_pass = config['Kucoin']['kucoin_api_pass']
    coinmarketcap_apikey = config['API']['coinmarketcap_apikey']
    blockfrost_apikey = config['API']['blockfrost_apikey']
    ada_address = config['Addresses']['ada_address']
    bnb_address = config['Addresses']['bnb_address']
    total = []
    USDT = 0.
    RUB = 0.
    # * Getting coins info from Binance
    try:
        client = binance.Client(binance_key, binance_sec)
        await client.load()
        accinfo = await client.fetch_account_information(receive_window=None)
        for coin in accinfo['balances']:
            if coin['asset'] == "USDT":
                USDT += float(coin['free'])
            elif coin['asset'] == "RUB":
                RUB += float(coin['free'])
            else:
                amount = float(coin['free'])
                ticker = coin['asset'] + "USDT"
                if amount > 0.000001:
                    print(ticker[:-4] + f" amount: {amount}")
                    coin.pop('locked')
                    coin['amount'] = float(coin.pop('free'))
                    total.append(coin)
        await client.close()
    except:
        print("Wrong Binance credentials.")
        bot.send_message(message.chat.id,
                         "You entered wrong Binance credentials.")

    # * Getting the amount of ADA on Yoroi
    link_cardano = "https://cardano-mainnet.blockfrost.io/api/v0/addresses/"
    headers = {'project_id': blockfrost_apikey}

    session = Session()
    session.headers.update(headers)
    try:
        response = session.get(link_cardano + ada_address)
        data = json.loads(response.text)
    except (ConnectionError, Timeout, TooManyRedirects) as e:
        print(e)
    try:
        ada_amount = float(data['amount'][0]['quantity'])
    except:
        ada_amount = 0
        bot.send_message(
            message.chat.id,
            "You entered wrong ADA address or Blockfrost API key.")
    if ada_amount > 1e+6:
        ada_amount /= 1e+6
    print(f"Found {ada_amount} ADA in Cardano Wallet")

    if not any(d['asset'] == 'ADA' for d in total):
        total.append({'asset': 'ADA', 'amount': ada_amount})
    else:
        for x in total:
            if x['asset'] == 'ADA':
                x['amount'] += ada_amount

    # * Getting the coins from BNB Wallet

    bnb_api_link = "https://dex.binance.org/api/v1/account/"

    response = urlopen(bnb_api_link + bnb_address)
    data_json = (json.loads(response.read()))['balances']
    for coin in data_json:
        amount = float(coin['free'])
        ticker = coin['symbol']
        if "CBB" in ticker:
            ticker = ticker[:-4]
        if amount > 0.000001:
            if not any(d['asset'] == ticker for d in total):
                total.append({'asset': ticker, 'amount': amount})
                print(
                    f"creating {ticker} with {amount} in total | From BNB Wallet"
                )
            else:
                for coin in total:
                    if coin['asset'] == ticker:
                        coin['amount'] += amount
                        print(
                            f"adding to {ticker} {amount} in total | From BNB Wallet"
                        )
                        break

    # *Getting coins from Kucoin
    try:
        client = Client(kucoin_key, kucoin_sec, kucoin_api_pass)
        kucoininfo = client.get_accounts()
        for coin in kucoininfo:
            if coin['type'] != 'trade':
                continue
            amount = float(coin['balance'])
            ticker = coin['currency']
            if amount > 0.000001 and ticker != "USDT":
                if not any(d['asset'] == ticker for d in total):
                    total.append({'asset': ticker, 'amount': amount})
                    print(
                        f"creating {ticker} with {amount} in total | From Kucoin"
                    )
                else:
                    for coin in total:
                        if coin['asset'] == ticker:
                            coin['amount'] += amount
                            print(
                                f"adding to {ticker} {amount} in total | From Kucoin"
                            )
                            break
    except:
        print("Wrong Kucoin credentials.")
        bot.send_message(message.chat.id,
                         "You entered wrong Kucoin credentials.")

    try:
        coinmarketcap_url = "https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest"
        alltickers = ""
        for coin in total:
            alltickers += (coin['asset'] + ",")
        alltickers = alltickers[:-1]
        parameters = {'symbol': alltickers}
        headers = {
            'Accepts': 'application/json',
            'X-CMC_PRO_API_KEY': coinmarketcap_apikey,
        }
        session = Session()
        session.headers.update(headers)
        response = session.get(coinmarketcap_url, params=parameters)
        data = json.loads(response.text)
        print("Got prices from Coinmarketcap")
        for coin in total:
            ticker = coin['asset']
            coin['price'] = data['data'][ticker]['quote']['USD']['price']
            coin['value_in_USD'] = coin['price'] * coin['amount']
        total = [
            i for i in total
            if not (i['value_in_USD'] < include_with_value_higher_than)
        ]
        total = sorted(total, key=itemgetter('value_in_USD'), reverse=True)

        balance = 0.
        for coin in total:
            balance += coin['value_in_USD']
        balance += USDT + (RUB / 74)
        balance = round(balance, 2)
        reply_msg = "*Total balance is " + str(balance) + " $*" + "\n\n"
        reply_msg += "*In coins:*\n"
        for coin in total:
            if coin['amount'] >= 1:
                amount = str(round(coin['amount'], 2))
            else:
                amount = str(round(coin['amount'], 6))
            reply_msg += coin['asset'] + ": " + amount + " | " + \
                str(round(coin['value_in_USD'], 2)) + " $\n"
        reply_msg += "\n*In fiat:*\n" + str(round(USDT, 2)) + " $\n"
        if RUB != 0:
            reply_msg += str(round(RUB, 2)) + " ₽\n"

        bot.reply_to(message, reply_msg, parse_mode='Markdown')
    except:
        print("Wrong API key for Coinmarketcap")
        bot.send_message(message.chat.id,
                         "You entered wrong Coinmarketcap API key.")
Beispiel #29
0
class KUCoin():

    global client
    global api_key
    global api_secret
    global api_pasphrase
    global balance_percent
    global pair
    global base_coin

    def __init__(self, balance_percent_value, coin_name):
        #api_key = '602e39d9a2644e0006e7e2c2'
        #603e5c8473b5c50006582528
        db = DB()

        config = db.connection.all()

        self.api_key = config[0]['api_key']
        #api_secret = '2db4483e-2a76-4c2c-b533-f64a80a25c6d'
        self.api_secret = config[0]['api_secret']
        self.api_passphrase = config[0]['api_pass']
        #, sandbox=True
        self.client = Client(self.api_key, self.api_secret,
                             self.api_passphrase)

        self.base_coin = config[1]['base_coin']
        self.balance_percent = balance_percent_value

        self.pair = coin_name + "-" + self.base_coin

    def getcurprice(self, pair):
        ticker = self.client.get_ticker(pair)
        return float(ticker['price'])

    def getAccounts(self, ):
        accounts = self.client.get_accounts()
        return accounts

    def get_max_position_available(self, currency, pair):
        accounts = self.getAccounts()

        for account in accounts:
            if account['currency'] == currency:
                balance = account['balance']
                break

        price = self.getcurprice(pair)

        to_use = (float(balance) * self.balance_percent) / 100

        decide_position_to_use = to_use / price

        return decide_position_to_use

    def create_sell_order(self, pair, quantity, price):

        order = self.client.create_limit_order(pair, Client.SIDE_SELL, price,
                                               quantity)
        print(order)
        return order

    def create_market_order(self):
        maxquantity = 0.0
        try:
            maxquantity = round(
                0.9 *
                self.get_max_position_available(self.base_coin, self.pair))
            if maxquantity > 0.0:
                # place a market buy order
                order = self.client.create_market_order(pair,
                                                        Client.SIDE_BUY,
                                                        size=maxquantity)
                print("Done")
                if not order['orderId']:
                    return "No Order Created Yet"
                else:
                    return "Max quantity " + str(
                        maxquantity) + "for Current Pair " + pair

        except KucoinAPIException as e:
            return e.message
Beispiel #30
0
        time.sleep(2)
        exit()


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Find price gap within a platform")
    parser.add_argument('--coin',
                        help='coin to be scanned, separated by dash(-).')
    parser.add_argument('--platform', help='Platform to trade.')
    parser.add_argument('--market',
                        default='BTC-ETH',
                        help='The two markets to trade against.')
    args = parser.parse_args()
    scan_coins = args.coin.split('-')

    # Get API credentials from AWS S3 bucket.
    abs_path = Path(Path(__file__).resolve().parents[1], CREDENTIALS_FILENAME)
    secret_downloader.download_secret(str(abs_path))
    with abs_path.open('r') as f:
        credentials = json.load(f)[args.platform]

    markets = args.market.split('-')

    client = Client(credentials['api_key'], credentials['secret_key'])
    helper = Helper(client, markets[0], markets[1])
    semaphore = threading.BoundedSemaphore(value=1)

    t3 = conrl()
    t3.start()