def getTakerFee(self): if self.exchange == 'coinbasepro': api = CBAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIPassphrase(), self.getAPIURL()) return api.getTakerFee() elif self.exchange == 'binance': api = BAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIURL()) return api.getTakerFee(self.getMarket()) else: return 0.005
def getOrders(self, market='', action='', status='all'): """Retrieves orders either live or simulation Parameters ---------- market : str, optional Filters orders by market action : str, optional Filters orders by action status : str Filters orders by status, defaults to 'all' """ # validate market is syntactically correct self._checkMarketSyntax(market) if action != '': # validate action is either a buy or sell if not action in ['buy', 'sell']: raise ValueError('Invalid order action.') # validate status is open, pending, done, active or all if not status in [ 'open', 'pending', 'done', 'active', 'all', 'filled' ]: raise ValueError('Invalid order status.') if self.app.getExchange() == 'binance': if self.mode == 'live': # if config is provided and live connect to Binance account portfolio model = BAuthAPI(self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIURL()) # retrieve orders from live Binance account portfolio self.orders = model.getOrders(market, action, status) return self.orders else: # return dummy orders if market == '': return self.orders else: return self.orders[self.orders['market'] == market] if self.app.getExchange() == 'coinbasepro': if self.mode == 'live': # if config is provided and live connect to Coinbase Pro account portfolio model = CBAuthAPI(self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL()) # retrieve orders from live Coinbase Pro account portfolio self.orders = model.getOrders(market, action, status) return self.orders else: # return dummy orders if market == '': return self.orders else: return self.orders[self.orders['market'] == market]
def marketSell(self, market, base_currency, sell_percent=100): if self.is_live == 1: if isinstance(sell_percent, int): if sell_percent > 0 and sell_percent < 100: base_currency = (sell_percent / 100) * base_currency if self.exchange == 'coinbasepro': api = CBAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIPassphrase(), self.getAPIURL()) return api.marketSell(market, base_currency) elif self.exchange == 'binance': api = BAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIURL()) return api.marketSell(market, base_currency) else: return None
def marketBuy(self, market, quote_currency, buy_percent=100): if self.is_live == 1: if isinstance(buy_percent, int): if buy_percent > 0 and buy_percent < 100: quote_currency = (buy_percent / 100) * quote_currency if self.exchange == 'coinbasepro': api = CBAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIPassphrase(), self.getAPIURL()) return api.marketBuy(market, self.truncate(quote_currency, 2)) elif self.exchange == 'binance': api = BAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIURL()) return api.marketBuy(market, quote_currency) else: return None
def getTakerFee(self): if self.isSimulation() is True and self.exchange == 'coinbasepro': return 0.005 # default lowest fee tier elif self.isSimulation() is True and self.exchange == 'binance': return 0.001 # default lowest fee tier elif self.exchange == 'coinbasepro': api = CBAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIPassphrase(), self.getAPIURL()) return api.getTakerFee() elif self.exchange == 'binance': api = BAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIURL()) return api.getTakerFee() else: return 0.005
def checkBalance(self, account, last_action=''): api = CBAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIPassphrase(), self.getAPIURL()) base_min_size, min_market_funds = api.marketMin( self.getMarket(), 0.001, 50) if last_action == 'SELL' and account.getBalance( self.getQuoteCurrency()) < min_market_funds: raise Exception( 'Insufficient available funds to place buy order: ' + str(account.getBalance(self.getQuoteCurrency())) + ' < ' + min_market_funds + self.getQuoteCurrency() + "\nNote: A manual limit order places a hold on available funds." ) elif last_action == 'BUY' and account.getBalance( self.getBaseCurrency()) < base_min_size: raise Exception( 'Insufficient available funds to place sell order: ' + str(account.getBalance(self.getBaseCurrency())) + ' < ' + base_min_size + self.getBaseCurrency() + "\nNote: A manual limit order places a hold on available funds." )
def getBalance(self, currency=''): """Retrieves balance either live or simulation Parameters ---------- currency: str, optional Filters orders by currency """ if self.app.getExchange() == 'binance': if self.mode == 'live': model = BAuthAPI(self.app.getAPIKey(), self.app.getAPISecret()) df = model.getAccount() if isinstance(df, pd.DataFrame): if currency == '': # retrieve all balances return df else: # retrieve balance of specified currency df_filtered = df[df['currency'] == currency]['available'] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ['EUR', 'GBP', 'USD']: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4)) else: return 0.0 else: # return dummy balances if currency == '': # retrieve all balances return self.balance else: if self.app.getExchange() == 'binance': self.balance = self.balance.replace('QUOTE', currency) else: # replace QUOTE and BASE placeholders if currency in ['EUR', 'GBP', 'USD']: self.balance = self.balance.replace( 'QUOTE', currency) else: self.balance = self.balance.replace( 'BASE', currency) if self.balance.currency[self.balance.currency.isin( [currency])].empty: self.balance.loc[len( self.balance)] = [currency, 0, 0, 0] # retrieve balance of specified currency df = self.balance df_filtered = df[df['currency'] == currency]['available'] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ['EUR', 'GBP', 'USD']: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4)) else: if self.mode == 'live': # if config is provided and live connect to Coinbase Pro account portfolio model = CBAuthAPI(self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL()) if currency == '': # retrieve all balances return model.getAccounts()[[ 'currency', 'balance', 'hold', 'available' ]] else: df = model.getAccounts() # retrieve balance of specified currency df_filtered = df[df['currency'] == currency]['available'] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ['EUR', 'GBP', 'USD']: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4)) else: # return dummy balances if currency == '': # retrieve all balances return self.balance else: # replace QUOTE and BASE placeholders if currency in ['EUR', 'GBP', 'USD']: self.balance = self.balance.replace('QUOTE', currency) elif currency in ['BCH', 'BTC', 'ETH', 'LTC', 'XLM']: self.balance = self.balance.replace('BASE', currency) if self.balance.currency[self.balance.currency.isin( [currency])].empty == True: self.balance.loc[len( self.balance)] = [currency, 0, 0, 0] # retrieve balance of specified currency df = self.balance df_filtered = df[df['currency'] == currency]['available'] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ['EUR', 'GBP', 'USD']: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( self.app.truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4))
def getOrders(self, market="", action="", status="all"): """Retrieves orders either live or simulation Parameters ---------- market : str, optional Filters orders by market action : str, optional Filters orders by action status : str Filters orders by status, defaults to 'all' """ # validate market is syntactically correct self._checkMarketSyntax(market) if action != "": # validate action is either a buy or sell if not action in ["buy", "sell"]: raise ValueError("Invalid order action.") # validate status is open, pending, done, active or all if not status in [ "open", "pending", "done", "active", "all", "filled" ]: raise ValueError("Invalid order status.") if self.app.getExchange() == Exchange.BINANCE: if self.mode == "live": # if config is provided and live connect to Binance account portfolio model = BAuthAPI( self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIURL(), recv_window=self.app.getRecvWindow(), ) # retrieve orders from live Binance account portfolio self.orders = model.getOrders(market, action, status) return self.orders else: # return dummy orders if market == "": return self.orders else: return self.orders[self.orders["market"] == market] if self.app.getExchange() == Exchange.KUCOIN: if self.mode == 'live': # if config is provided and live connect to Kucoin account portfolio model = KAuthAPI( self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL(), use_cache=self.app.useKucoinCache(), ) # retrieve orders from live Kucoin account portfolio self.orders = model.getOrders(market, action, status) return self.orders else: if market == '': return self.orders else: return self.orders[self.orders['market'] == market] if self.app.getExchange() == Exchange.COINBASEPRO: if self.mode == "live": # if config is provided and live connect to Coinbase Pro account portfolio model = CBAuthAPI( self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL(), ) # retrieve orders from live Coinbase Pro account portfolio self.orders = model.getOrders(market, action, status) return self.orders else: # return dummy orders if market == "": return self.orders else: if "market" in self.orders: return self.orders[self.orders["market"] == market] else: return pd.DataFrame() if self.app.getExchange() == Exchange.DUMMY: return self.orders[[ "created_at", "market", "action", "type", "size", "filled", "fees", "price", "status", ]]
def getBalance(self, currency=""): """Retrieves balance either live or simulation Parameters ---------- currency: str, optional Filters orders by currency """ if self.app.getExchange() == Exchange.KUCOIN: if self.mode == 'live': model = KAuthAPI( self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL(), use_cache=self.app.useKucoinCache(), ) trycnt, maxretry = (0, 5) while trycnt <= maxretry: df = model.getAccounts() if isinstance(df, pd.DataFrame) and len(df) > 0: if currency == '': # retrieve all balances return df else: # retrieve balance of specified currency df_filtered = df[df['currency'] == currency]['available'] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ['EUR', 'GBP', 'USD']: return float( truncate( float( df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( truncate( float( df[df['currency'] == currency] ['available'].values[0]), 4)) else: time.sleep(5) trycnt += 1 else: return 0.0 else: # return dummy balances if currency == '': # retrieve all balances return self.balance else: self.balance = self.balance.replace('QUOTE', currency) if self.balance.currency[self.balance.currency.isin( [currency])].empty: self.balance.loc[len( self.balance)] = [currency, 0, 0, 0] # retrieve balance of specified currency df = self.balance df_filtered = df[df['currency'] == currency]['available'] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ['EUR', 'GBP', 'USD']: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4)) elif self.app.getExchange() == Exchange.BINANCE: if self.mode == "live": model = BAuthAPI( self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIURL(), recv_window=self.app.getRecvWindow(), ) df = model.getAccount() if isinstance(df, pd.DataFrame): if currency == "": # retrieve all balances return df else: # return nil if dataframe is empty if len(df) == 0: return 0.0 # retrieve balance of specified currency df_filtered = df[df["currency"] == currency]["available"] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ["EUR", "GBP", "USD"]: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4)) else: return 0.0 else: # return dummy balances if currency == "": # retrieve all balances return self.balance else: if self.app.getExchange() == Exchange.BINANCE: self.balance = self.balance.replace("QUOTE", currency) else: # replace QUOTE and BASE placeholders if currency in ["EUR", "GBP", "USD"]: self.balance = self.balance.replace( "QUOTE", currency) else: self.balance = self.balance.replace( "BASE", currency) if self.balance.currency[self.balance.currency.isin( [currency])].empty: self.balance.loc[len( self.balance)] = [currency, 0, 0, 0] # retrieve balance of specified currency df = self.balance df_filtered = df[df["currency"] == currency]["available"] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ["EUR", "GBP", "USD"]: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4)) elif self.app.getExchange() == Exchange.COINBASEPRO: if self.mode == "live": # if config is provided and live connect to Coinbase Pro account portfolio model = CBAuthAPI( self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL(), ) trycnt, maxretry = (0, 5) while trycnt <= maxretry: df = model.getAccounts() if len(df) > 0: # retrieve all balances, but check the resp if currency == "" and "balance" not in df: time.sleep(5) trycnt += 1 # retrieve all balances and return elif currency == "": return df else: # retrieve balance of specified currency df_filtered = df[df["currency"] == currency]["available"] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ["EUR", "GBP", "USD"]: return float( truncate( float( df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( truncate( float( df[df['currency'] == currency] ['available'].values[0]), 4)) else: time.sleep(5) trycnt += 1 else: return 0.0 else: # return dummy balances if currency == "": # retrieve all balances return self.balance else: # replace QUOTE and BASE placeholders if currency in ["EUR", "GBP", "USD"]: self.balance = self.balance.replace("QUOTE", currency) elif currency in ["BCH", "BTC", "ETH", "LTC", "XLM"]: self.balance = self.balance.replace("BASE", currency) if (self.balance.currency[self.balance.currency.isin( [currency])].empty == True): self.balance.loc[len( self.balance)] = [currency, 0, 0, 0] # retrieve balance of specified currency df = self.balance df_filtered = df[df["currency"] == currency]["available"] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) if currency in ["EUR", "GBP", "USD"]: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 2)) else: return float( truncate( float(df[df['currency'] == currency] ['available'].values[0]), 4)) else: # dummy account if currency == "": # retrieve all balances return self.balance else: # retrieve balance of specified currency df = self.balance df_filtered = df[df["currency"] == currency]["available"] if len(df_filtered) == 0: # return nil balance if no positive balance was found return 0.0 else: # return balance of specified currency (if positive) return float( df[df["currency"] == currency]["available"].values[0])
def getLastBuy(self) -> dict: """Retrieves the last exchange buy order and returns a dictionary""" try: if self.exchange == 'coinbasepro': api = CBAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIPassphrase(), self.getAPIURL()) orders = api.getOrders(self.getMarket(), '', 'done') if len(orders) == 0: return None last_order = orders.tail(1) if last_order['action'].values[0] != 'buy': return None return { 'side': 'buy', 'market': self.getMarket(), 'size': float(last_order['size']), 'filled': float(last_order['filled']), 'price': float(last_order['price']), 'fee': float(last_order['fees']), 'date': str( pd.DatetimeIndex( pd.to_datetime( last_order['created_at']).dt.strftime( '%Y-%m-%dT%H:%M:%S.%Z'))[0]) } elif self.exchange == 'binance': api = BAuthAPI(self.getAPIKey(), self.getAPISecret(), self.getAPIURL()) orders = api.getOrders(self.getMarket()) if len(orders) == 0: return None last_order = orders.tail(1) if last_order['action'].values[0] != 'buy': return None return { 'side': 'buy', 'market': self.getMarket(), 'size': float(last_order['size']), 'filled': float(last_order['filled']), 'price': float(last_order['price']), 'fees': float(last_order['size'] * 0.001), 'date': str( pd.DatetimeIndex( pd.to_datetime( last_order['created_at']).dt.strftime( '%Y-%m-%dT%H:%M:%S.%Z'))[0]) } else: return None except Exception: return None
def sell(self, cryptoMarket, fiatMarket, cryptoAmount, manualPrice=0.00000000): """Places a sell order either live or simulation Parameters ---------- cryptoMarket: str Crypto market you wish to purchase fiatMarket, str QUOTE market funding the purchase fiatAmount, float QUOTE amount of crypto currency to purchase manualPrice, float Used for simulations specifying the live price to purchase """ if self.app.getExchange() == 'binance': # validate crypto market is syntactically correct p = re.compile(r"^[A-Z]{3,8}$") if not p.match(cryptoMarket): raise TypeError('Binance crypto market is invalid.') # validate fiat market is syntactically correct p = re.compile(r"^[A-Z]{3,8}$") if not p.match(fiatMarket): raise TypeError('Binance fiat market is invalid.') else: # crypto market should be either BCH, BTC, ETH, LTC or XLM if cryptoMarket not in ['BCH', 'BTC', 'ETH', 'LTC', 'XLM']: raise Exception( 'Invalid crypto market: BCH, BTC, ETH, LTC, ETH, or XLM') # fiat market should be either EUR, GBP, or USD if fiatMarket not in ['EUR', 'GBP', 'USD']: raise Exception('Invalid QUOTE market: EUR, GBP, USD') # reconstruct the exchange market using crypto and fiat inputs if self.app.getExchange() == 'binance': market = cryptoMarket + fiatMarket else: market = cryptoMarket + '-' + fiatMarket # crypto amount must be an integer or float if not isinstance(cryptoAmount, float) and not isinstance( cryptoAmount, int): raise TypeError('Crypto amount not numeric.') # crypto amount must be positive if cryptoAmount <= 0: raise Exception('Invalid crypto amount.') if self.app.getExchange() == 'binance': if self.mode == 'live': # execute a live market buy resp = self.client.order_market_sell(symbol=market, quantity=cryptoAmount) # TODO: not finished print(resp) else: # crypto amount should exceed balance if cryptoAmount > self.getBalance(cryptoMarket): raise Exception('Insufficient funds.') # manual price must be an integer or float if not isinstance(manualPrice, float) and not isinstance( manualPrice, int): raise TypeError('Optional manual price not numeric.') # calculate purchase fees fee = cryptoAmount * 0.005 cryptoAmountMinusFee = cryptoAmount - fee price = manualPrice # if manualPrice is non-positive retrieve the current live price if manualPrice <= 0: resp = requests.get( 'https://api-public.sandbox.pro.coinbase.com/products/' + market + '/ticker') if resp.status_code != 200: raise Exception('GET /products/' + market + '/ticker {}'.format(resp.status_code)) resp.raise_for_status() json = resp.json() price = float(json['price']) total = price * cryptoAmountMinusFee # append dummy order into orders dataframe ts = pd.Timestamp.now() price = ((price * cryptoAmount) * 100) / (cryptoAmount * 100) order = pd.DataFrame([[ '', market, 'sell', 'market', cryptoAmountMinusFee, float('{:.8f}'.format(total)), 'done', '{:.8f}'.format( float(price)) ]], columns=[ 'created_at', 'market', 'action', 'type', 'size', 'value', 'status', 'price' ], index=[ts]) order['created_at'] = order.index self.orders = pd.concat( [self.orders, pd.DataFrame(order)], ignore_index=False) # update the dummy fiat balance self.balance.loc[ self.balance['currency'] == fiatMarket, 'balance'] = self.getBalance(fiatMarket) + total self.balance.loc[ self.balance['currency'] == fiatMarket, 'available'] = self.getBalance(fiatMarket) + total # update the dummy crypto balance self.balance.loc[ self.balance['currency'] == cryptoMarket, 'balance'] = self.getBalance(cryptoMarket) - cryptoAmount self.balance.loc[ self.balance['currency'] == cryptoMarket, 'available'] = self.getBalance(cryptoMarket) - cryptoAmount else: if self.mode == 'live': # connect to Coinbase Pro API live model = CBAuthAPI(self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL()) # execute a live market sell resp = model.marketSell(market, float(self.getBalance(cryptoMarket))) # TODO: not finished print(resp) else: # crypto amount should exceed balance if cryptoAmount > self.getBalance(cryptoMarket): raise Exception('Insufficient funds.') # manual price must be an integer or float if not isinstance(manualPrice, float) and not isinstance( manualPrice, int): raise TypeError('Optional manual price not numeric.') # calculate purchase fees fee = cryptoAmount * 0.005 cryptoAmountMinusFee = cryptoAmount - fee price = manualPrice if manualPrice <= 0: # if manualPrice is non-positive retrieve the current live price resp = requests.get( 'https://api-public.sandbox.pro.coinbase.com/products/' + market + '/ticker') if resp.status_code != 200: raise Exception('GET /products/' + market + '/ticker {}'.format(resp.status_code)) resp.raise_for_status() json = resp.json() price = float(json['price']) total = price * cryptoAmountMinusFee # append dummy order into orders dataframe ts = pd.Timestamp.now() price = ((price * cryptoAmount) * 100) / (cryptoAmount * 100) order = pd.DataFrame([[ market, 'sell', 'market', cryptoAmountMinusFee, float('{:.8f}'.format(total)), 'done', price ]], columns=[ 'market', 'action', 'type', 'size', 'value', 'status', 'price' ], index=[ts]) order['created_at'] = order.index self.orders = pd.concat( [self.orders, pd.DataFrame(order)], ignore_index=False) # update the dummy fiat balance self.balance.loc[ self.balance['currency'] == fiatMarket, 'balance'] = self.getBalance(fiatMarket) + total self.balance.loc[ self.balance['currency'] == fiatMarket, 'available'] = self.getBalance(fiatMarket) + total # update the dummy crypto balance self.balance.loc[ self.balance['currency'] == cryptoMarket, 'balance'] = self.getBalance(cryptoMarket) - cryptoAmount self.balance.loc[ self.balance['currency'] == cryptoMarket, 'available'] = self.getBalance(cryptoMarket) - cryptoAmount
config_list = [config] for config_item in config_list: if "cryptoMarket" in config: base_currency = config["cryptoMarket"] elif "base_currency" in config: base_currency = config["base_currency"] if "fiatMarket" in config: quote_currency = config["fiatMarket"] elif "base_currency" in config: quote_currency = config["quote_currency"] market = base_currency + "-" + quote_currency api = CBAuthAPI(api_key, api_secret, api_pass) orders = api.getOrders() df = pd.concat([df, orders]) transfers = api.getTransfers() df = pd.concat([df, transfers]) df["created_at"] = df["created_at"].map( lambda x: re.sub(r"\.\d{1,6}\+00$", "", str(x)) ) df["created_at"] = df["created_at"].map(lambda x: re.sub(r"\+00:00$", "", str(x))) try: df.to_csv("profitandloss.csv", index=False) except OSError: