def markets(): html = "" api = BPublicAPI() resp = api.getMarkets24HrStats() for market in resp: if market["lastPrice"] > market["openPrice"]: html += f""" <tr> <th class="table-success" scope="row"><a class="text-dark" href="/binance/{market['symbol']}">{market['symbol']}</a></th> <td class="table-success" style="border-left: 1px solid #000;">{market['priceChangePercent']}%</td> <td class="table-success">{market['openPrice']}</td> <td class="table-success">{market['highPrice']}</td> <td class="table-success">{market['lowPrice']}</td> <td class="table-success">{market['lastPrice']}</td> <td class="table-success">{market['quoteVolume']}</td> </tr> """ elif market["lastPrice"] < market["openPrice"]: html += f""" <tr> <th class="table-danger" scope="row"><a class="text-dark" href="/binance/{market['symbol']}">{market['symbol']}</a></th> <td class="table-danger" style="border-left: 1px solid #000;">{market['priceChangePercent']}%</td> <td class="table-danger">{market['openPrice']}</td> <td class="table-danger">{market['highPrice']}</td> <td class="table-danger">{market['lowPrice']}</td> <td class="table-danger">{market['lastPrice']}</td> <td class="table-danger">{market['quoteVolume']}</td> </tr> """ else: html += f""" <tr> <th scope="row"><a class="text-dark" href="/binance/{market['symbol']}">{market['symbol']}</a></th> <td style="border-left: 1px solid #000;">{market['priceChangePercent']}%</td> <td>{market['openPrice']}</td> <td>{market['highPrice']}</td> <td>{market['lowPrice']}</td> <td>{market['lastPrice']}</td> <td>{market['quoteVolume']}</td> </tr> """ return html
def test_instantiate_publicapi_without_error(): exchange = PublicAPI() assert type(exchange) is PublicAPI
from models.exchange.Granularity import Granularity from models.exchange.ExchangesEnum import Exchange GRANULARITY = Granularity(Granularity.ONE_HOUR) try: with open("scanner.json", encoding='utf8') as json_file: config = json.load(json_file) except IOError as err: print(err) for exchange in config: ex = Exchange(exchange) app = PyCryptoBot(exchange=ex) for quote in config[ex.value]["quote_currency"]: if ex == Exchange.BINANCE: api = BPublicAPI() elif ex == Exchange.COINBASEPRO: api = CPublicAPI() elif ex == Exchange.KUCOIN: api = KPublicAPI() else: raise ValueError(f"Invalid exchange: {ex}") markets = [] resp = api.getMarkets24HrStats() if ex == Exchange.BINANCE: for row in resp: if row["symbol"].endswith(quote): markets.append(row) elif ex == Exchange.COINBASEPRO: for market in resp:
def technical_analysis(exchange: str, market: str, g1, g2, g3) -> str: if exchange == 'binance': if not isBinanceMarketValid(market): return f""" {header()} <h4>Invalid Market!</h4> <div class="d-grid gap-2 d-md-flex justify-content-md-end"> <a class="text-dark" href='/{exchange}'><button class="btn btn-primary me-md-2" type="button">Go Back</button></a> </div> {footer()} """ elif exchange == 'coinbasepro': if not isCoinbaseMarketValid(market): return f""" {header()} <h4>Invalid Market!</h4> <div class="d-grid gap-2 d-md-flex justify-content-md-end"> <a class="text-dark" href='/{exchange}'><button class="btn btn-primary me-md-2" type="button">Go Back</button></a> </div> {footer()} """ else: return "Invalid Exchange!" if exchange == 'binance': api = BPublicAPI() if exchange == 'coinbasepro': api = CPublicAPI() ticker = api.getTicker(market) ta = TechnicalAnalysis(api.getHistoricalData(market, g1, None)) ta.addAll() df_15m = ta.getDataFrame() df_15m_last = df_15m.tail(1) ta = TechnicalAnalysis(api.getHistoricalData(market, g2, None)) ta.addAll() df_1h = ta.getDataFrame() df_1h_last = df_1h.tail(1) ta = TechnicalAnalysis(api.getHistoricalData(market, g3, None)) ta.addAll() df_6h = ta.getDataFrame() df_6h_last = df_6h.tail(1) if exchange == 'binance': exchange_name = 'Binance' elif exchange == 'coinbasepro': exchange_name = 'Coinbase Pro' rsi14_15m_class = 'table-normal' rsi14_15m_desc = 'Uneventful' if df_15m_last['rsi14'].values[0] > 70: rsi14_15m_class = 'table-danger' rsi14_15m_desc = 'Overbought (Sell)' elif df_15m_last['rsi14'].values[0] < 30: rsi14_15m_class = 'table-success' rsi14_15m_desc = 'Oversold (Buy)' rsi14_1h_class = 'table-normal' rsi14_1h_desc = 'Uneventful' if df_1h_last['rsi14'].values[0] > 70: rsi14_1h_class = 'table-danger' rsi14_1h_desc = 'Overbought (Sell)' elif df_1h_last['rsi14'].values[0] < 30: rsi14_1h_class = 'table-success' rsi14_1h_desc = 'Oversold (Buy)' rsi14_6h_class = 'table-normal' rsi14_6h_desc = 'Uneventful' if df_6h_last['rsi14'].values[0] > 70: rsi14_6h_class = 'table-danger' rsi14_6h_desc = 'Overbought (Sell)' elif df_6h_last['rsi14'].values[0] < 30: rsi14_6h_class = 'table-success' rsi14_6h_desc = 'Oversold (Buy)' stochrsi14_15m_class = 'table-normal' stochrsi14_15m_desc = 'Uneventful' if df_6h_last['stochrsi14'].values[0] > 0.8: stochrsi14_6h_class = 'table-danger' stochrsi14_6h_desc = 'Overbought (Sell)' elif df_6h_last['stochrsi14'].values[0] < 0.2: stochrsi14_6h_class = 'table-success' stochrsi14_6h_desc = 'Oversold (Buy)' stochrsi14_1h_class = 'table-normal' stochrsi14_1h_desc = 'Uneventful' if df_1h_last['stochrsi14'].values[0] > 0.8: stochrsi14_1h_class = 'table-danger' stochrsi14_1h_desc = 'Overbought (Sell)' elif df_1h_last['stochrsi14'].values[0] < 0.2: stochrsi14_1h_class = 'table-success' stochrsi14_1h_desc = 'Oversold (Buy)' stochrsi14_6h_class = 'table-normal' stochrsi14_6h_desc = 'Uneventful' if df_6h_last['stochrsi14'].values[0] > 0.8: stochrsi14_6h_class = 'table-danger' stochrsi14_6h_desc = 'Overbought (Sell)' elif df_6h_last['stochrsi14'].values[0] < 0.2: stochrsi14_6h_class = 'table-success' stochrsi14_6h_desc = 'Oversold (Buy)' williamsr14_15m_class = 'table-normal' williamsr14_15m_desc = 'Uneventful' if df_15m_last['williamsr14'].values[0] > -20: williamsr14_15m_class = 'table-danger' williamsr14_15m_desc = 'Overbought (Sell)' elif df_15m_last['williamsr14'].values[0] < -80: williamsr14_15m_class = 'table-success' williamsr14_15m_desc = 'Oversold (Buy)' williamsr14_1h_class = 'table-normal' williamsr14_1h_desc = 'Uneventful' if df_1h_last['williamsr14'].values[0] > -20: williamsr14_1h_class = 'table-danger' williamsr14_1h_desc = 'Overbought (Sell)' elif df_1h_last['williamsr14'].values[0] < -80: williamsr14_1h_class = 'table-success' williamsr14_1h_desc = 'Oversold (Buy)' williamsr14_6h_class = 'table-normal' williamsr14_6h_desc = 'Uneventful' if df_6h_last['williamsr14'].values[0] > -20: williamsr14_6h_class = 'table-danger' williamsr14_6h_desc = 'Overbought (Sell)' elif df_6h_last['williamsr14'].values[0] < -80: williamsr14_6h_class = 'table-success' williamsr14_6h_desc = 'Oversold (Buy)' adx14_15m_class = 'table-normal' adx14_15m_desc = 'Normal Trend' if df_15m_last['adx14'].values[0] > 25 and df_15m_last['ema12'].values[0] >= df_15m_last['ema26'].values[0]: adx14_15m_class = 'table-success' adx14_15m_desc = 'Strong Trend Up' elif df_15m_last['adx14'].values[0] > 25 and df_15m_last['ema12'].values[0] < df_15m_last['ema26'].values[0]: adx14_15m_class = 'table-danger' adx14_15m_desc = 'Strong Trend Down' elif df_15m_last['adx14'].values[0] < 20 and df_15m_last['ema12'].values[0] >= df_15m_last['ema26'].values[0]: adx14_15m_class = 'table-success' adx14_15m_desc = 'Weak Trend Up' elif df_15m_last['adx14'].values[0] < 20 and df_15m_last['ema12'].values[0] < df_15m_last['ema26'].values[0]: adx14_15m_class = 'table-danger' adx14_15m_desc = 'Weak Trend Up' adx14_1h_class = 'table-normal' adx14_1h_desc = 'Normal Trend' if df_1h_last['adx14'].values[0] > 25 and df_1h_last['ema12'].values[0] >= df_1h_last['ema26'].values[0]: adx14_1h_class = 'table-success' adx14_1h_desc = 'Strong Trend Up' elif df_1h_last['adx14'].values[0] > 25 and df_1h_last['ema12'].values[0] < df_1h_last['ema26'].values[0]: adx14_1h_class = 'table-danger' adx14_1h_desc = 'Strong Trend Down' elif df_1h_last['adx14'].values[0] < 20 and df_1h_last['ema12'].values[0] >= df_1h_last['ema26'].values[0]: adx14_1h_class = 'table-success' adx14_1h_desc = 'Weak Trend Up' elif df_1h_last['adx14'].values[0] < 20 and df_1h_last['ema12'].values[0] < df_1h_last['ema26'].values[0]: adx14_1h_class = 'table-danger' adx14_1h_desc = 'Weak Trend Up' adx14_6h_class = 'table-normal' adx14_6h_desc = 'Normal Trend' if df_6h_last['adx14'].values[0] > 25 and df_6h_last['ema12'].values[0] >= df_6h_last['ema26'].values[0]: adx14_6h_class = 'table-success' adx14_6h_desc = 'Strong Trend Up' elif df_6h_last['adx14'].values[0] > 25 and df_6h_last['ema12'].values[0] < df_6h_last['ema26'].values[0]: adx14_6h_class = 'table-danger' adx14_6h_desc = 'Strong Trend Down' elif df_6h_last['adx14'].values[0] < 20 and df_6h_last['ema12'].values[0] >= df_6h_last['ema26'].values[0]: adx14_6h_class = 'table-success' adx14_6h_desc = 'Weak Trend Up' elif df_6h_last['adx14'].values[0] < 20 and df_6h_last['ema12'].values[0] < df_6h_last['ema26'].values[0]: adx14_6h_class = 'table-danger' adx14_6h_desc = 'Weak Trend Up' def arima_predictions(even_rows: bool = True): results_ARIMA = ta.seasonalARIMAModel() start_date = df_1h.last_valid_index() end_date = start_date + datetime.timedelta(days=3) arima_pred = results_ARIMA.predict( start=str(start_date), end=str(end_date), dynamic=True ) if even_rows: arima_pred_rows = arima_pred.iloc[::2] else: arima_pred_rows = arima_pred.iloc[1::2] html = "" for index, pred in arima_pred_rows.iteritems(): html += f""" <tbody> <tr class={'table-success' if pred >= ticker[1] else 'table-danger'}> <td>{index}</td> <td>{pred}</td> </tr> </tbody> """ return html return f"""
def buy(self, cryptoMarket, fiatMarket, fiatAmount=0, manualPrice=0.00000000): """Places a buy 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 """ # fiat funding amount must be an integer or float if not isinstance(fiatAmount, float) and not isinstance( fiatAmount, int): raise TypeError('QUOTE amount not numeric.') # fiat funding amount must be positive if fiatAmount <= 0: raise Exception('Invalid QUOTE amount.') 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 if self.app.getExchange() == 'binance': if self.mode == 'live': # execute a live market buy resp = self.client.order_market_buy(symbol=market, quantity=fiatAmount) # TODO: not finished print(resp) else: # fiat amount should exceed balance if fiatAmount > self.getBalance(fiatMarket): 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.') price = manualPrice # if manualPrice is non-positive retrieve the current live price if manualPrice <= 0: if self.app.getExchange() == 'binance': api = BPublicAPI() price = api.getTicker(market)[1] else: 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']) # calculate purchase fees fee = fiatAmount * 0.005 fiatAmountMinusFee = fiatAmount - fee total = float(fiatAmountMinusFee / float(price)) # append dummy order into orders dataframe ts = pd.Timestamp.now() price = (fiatAmountMinusFee * 100) / (total * 100) order = pd.DataFrame([[ '', market, 'buy', 'market', float('{:.8f}'.format(total)), fiatAmountMinusFee, '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) - fiatAmount self.balance.loc[ self.balance['currency'] == fiatMarket, 'available'] = self.getBalance(fiatMarket) - fiatAmount # update the dummy crypto balance self.balance.loc[self.balance['currency'] == cryptoMarket, 'balance'] = self.getBalance(cryptoMarket) + ( fiatAmountMinusFee / price) self.balance.loc[ self.balance['currency'] == cryptoMarket, 'available'] = self.getBalance(cryptoMarket) + ( fiatAmountMinusFee / price) else: if self.mode == 'live': # connect to coinbase pro api (authenticated) model = CBAuthAPI(self.app.getAPIKey(), self.app.getAPISecret(), self.app.getAPIPassphrase(), self.app.getAPIURL()) # execute a live market buy if fiatAmount > 0: resp = model.marketBuy(market, fiatAmount) else: resp = model.marketBuy(market, float(self.getBalance(fiatMarket))) # TODO: not finished print(resp) else: # fiat amount should exceed balance if fiatAmount > self.getBalance(fiatMarket): 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.') 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']) # calculate purchase fees fee = fiatAmount * 0.005 fiatAmountMinusFee = fiatAmount - fee total = float(fiatAmountMinusFee / price) # append dummy order into orders dataframe ts = pd.Timestamp.now() price = (fiatAmountMinusFee * 100) / (total * 100) order = pd.DataFrame([[ '', market, 'buy', 'market', float('{:.8f}'.format(total)), fiatAmountMinusFee, 'done', 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) - fiatAmount self.balance.loc[ self.balance['currency'] == fiatMarket, 'available'] = self.getBalance(fiatMarket) - fiatAmount # update the dummy crypto balance self.balance.loc[self.balance['currency'] == cryptoMarket, 'balance'] = self.getBalance(cryptoMarket) + ( fiatAmountMinusFee / price) self.balance.loc[ self.balance['currency'] == cryptoMarket, 'available'] = self.getBalance(cryptoMarket) + ( fiatAmountMinusFee / price)