def marketSell(self, market: str='', base_quantity: float=0) -> list: """Executes a market sell providing a crypto amount""" # validates the market is syntactically correct if not self._isMarketValid(market): raise ValueError('Binance market is invalid.') if not isinstance(base_quantity, int) and not isinstance(base_quantity, float): raise TypeError('The crypto amount is not numeric.') try: df_filters = self.getMarketInfoFilters(market) step_size = float(df_filters.loc[df_filters['filterType'] == 'LOT_SIZE']['stepSize']) precision = int(round(-math.log(step_size, 10), 0)) # remove fees base_quantity = base_quantity - (base_quantity * self.getTradeFee(market)) # execute market sell stepper = 10.0 ** precision truncated = math.trunc(stepper * base_quantity) / stepper Logger.info('Order quantity after rounding and fees: ' + str(truncated)) return self.client.order_market_sell(symbol=market, quantity=truncated) except Exception as err: ts = datetime.now().strftime("%d-%m-%Y %H:%M:%S") Logger.error(ts + ' Binance ' + ' marketSell ' + str(err)) return []
def line(self, left_text, right_text): left_slice = left_text[slice(self.max_left)] right_slice = right_text[slice(self.max_right)] left_space = (' ' * (self.max_left - len(left_slice))) right_space = (' ' * (self.max_right - len(right_slice))) Logger.info( f'| {left_space}{left_slice} : {right_slice}{right_space} |')
def renderPercentageChangeHistogram(self, show_desc=True): """Render Percentage Change Histogram Parameters ---------- saveOnly : bool Save the figure without displaying it """ # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity fig, ax = plt.subplots(ncols=1, figsize=(12, 6)) # pylint: disable=unused-variable fig.autofmt_xdate() ax = plt.subplot(111) df.close_pc.hist(bins=50) ax.set_title("Close Percent Change") plt.xlabel(market + " - " + str(granularity)) plt.xticks(rotation=90) plt.tight_layout() plt.legend() plt.show() if show_desc is True: Logger.info(df["close_pc"].describe())
def handle_api_error(self, err: str, reason: str) -> dict: if self.debug: if self.die_on_api_error: raise SystemExit(err) else: Logger.debug(err) return {} else: if self.die_on_api_error: raise SystemExit(f"{reason}: {self._api_url}") else: Logger.info(f"{reason}: {self._api_url}") return {}
def handle_api_error(self, err: str, reason: str) -> pd.DataFrame: """Handle API errors""" if self.debug: if self.die_on_api_error: raise SystemExit(err) else: Logger.error(err) return pd.DataFrame() else: if self.die_on_api_error: raise SystemExit(f"{reason}: {self._api_url}") else: Logger.info(f"{reason}: {self._api_url}") return pd.DataFrame()
def checkTrailingBuy(self, app, state, price: float = 0.0): # If buy signal, save the price and check if it decreases before buying. trailing_buy_logtext = "" waitpcnttext = "" immediate_action = False if state.trailing_buy == 0: state.waiting_buy_price = price pricechange = 0 elif state.trailing_buy == 1 and state.waiting_buy_price > 0: pricechange = ((price - state.waiting_buy_price) / state.waiting_buy_price * 100) if price < state.waiting_buy_price: state.waiting_buy_price = price waitpcnttext += f"Price decreased - resetting wait price. " waitpcnttext += f"** {app.getMarket()} - " if pricechange < app.getTrailingBuyPcnt( ): # get pcnt from config, if not, use 0% state.action = "WAIT" state.trailing_buy = 1 if app.getTrailingBuyPcnt() > 0: trailing_buy_logtext = f" - Wait Chg: {_truncate(pricechange,2)}%/{app.getTrailingBuyPcnt()}%" waitpcnttext += f"Waiting to buy until {state.waiting_buy_price} increases {app.getTrailingBuyPcnt()}% - change {_truncate(pricechange,2)}%" else: trailing_buy_logtext = f" - Wait Chg: {_truncate(pricechange,2)}%" waitpcnttext += f"Waiting to buy until {state.waiting_buy_price} stops decreasing - change {_truncate(pricechange,2)}%" else: state.action = "BUY" state.trailing_buy = 1 if app.trailingImmediateBuy(): immediate_action = True trailing_buy_logtext = f" - Ready Chg: {_truncate(pricechange,2)}%/{app.getTrailingBuyPcnt()}%" waitpcnttext += f"Ready to buy. {state.waiting_buy_price} change of {_truncate(pricechange,2)}% is above setting of {app.getTrailingBuyPcnt()}%" if app.isVerbose() and (not app.isSimulation() or (app.isSimulation() and not app.simResultOnly())): Logger.info(waitpcnttext) return state.action, state.trailing_buy, trailing_buy_logtext, immediate_action
def printSupportResistanceLevel(self, price: float=0) -> None: if isinstance(price, int) or isinstance(price, float): df = self.getSupportResistanceLevels() if len(df) > 0: df_last = df.tail(1) if float(df_last[0]) < price: Logger.info(' Support level of ' + str(df_last[0]) + ' formed at ' + str(df_last.index[0])) elif float(df_last[0]) > price: Logger.info(' Resistance level of ' + str(df_last[0]) + ' formed at ' + str(df_last.index[0])) else: Logger.info(' Support/Resistance level of ' + str(df_last[0]) + ' formed at ' + str(df_last.index[0]))
def center(self, text): text_slice = text[slice(self.width - 4)] left_space = ' ' * int((self.width - len(text_slice) - 2) / 2) right_space = ' ' * (self.width - len(text_slice) - len(left_space) - 2) Logger.info(f'|{left_space}{text_slice}{right_space}|')
def doubleLine(self): Logger.info('=' * self.width)
def singleLine(self): Logger.info('-' * self.width)
def getHistoricalData(self, market: str=DEFAULT_MARKET, granularity: str=DEFAULT_GRANULARITY, iso8601start: str='', iso8601end: str='') -> pd.DataFrame: # validates the market is syntactically correct if not self._isMarketValid(market): raise TypeError('Binance market required.') # validates granularity is a string if not isinstance(granularity, str): raise TypeError('Granularity string required.') # validates the granularity is supported by Binance if not granularity in SUPPORTED_GRANULARITY: raise TypeError('Granularity options: ' + ", ".join(map(str, SUPPORTED_GRANULARITY))) # validates the ISO 8601 start date is a string (if provided) if not isinstance(iso8601start, str): raise TypeError('ISO8601 start integer as string required.') # validates the ISO 8601 end date is a string (if provided) if not isinstance(iso8601end, str): raise TypeError('ISO8601 end integer as string required.') # if only a start date is provided if iso8601start != '' and iso8601end == '': try: multiplier = MULTIPLIER_EQUIVALENTS[SUPPORTED_GRANULARITY.index(granularity)] except: multiplier = 1 # calculate the end date using the granularity iso8601end = str((datetime.strptime(iso8601start, '%Y-%m-%dT%H:%M:%S.%f') + timedelta(minutes=granularity * multiplier)).isoformat()) if iso8601start != '' and iso8601end != '': Logger.info('Attempting to retrieve data from ' + iso8601start) resp = self.client.get_historical_klines(market, granularity, iso8601start, iso8601end) if len(resp) > 300: resp = resp[:300] else: # TODO: replace with a KLINE_MESSAGE_FOO equivalent if granularity == '1m': resp = self.client.get_historical_klines(market, granularity, '12 hours ago UTC') resp = resp[-300:] elif granularity == '5m': resp = self.client.get_historical_klines(market, granularity, '2 days ago UTC') resp = resp[-300:] elif granularity == '15m': resp = self.client.get_historical_klines(market, granularity, '4 days ago UTC') resp = resp[-300:] elif granularity == '1h': resp = self.client.get_historical_klines(market, granularity, '13 days ago UTC') resp = resp[-300:] elif granularity == '6h': resp = self.client.get_historical_klines(market, granularity, '75 days ago UTC') resp = resp[-300:] elif granularity == '1d': resp = self.client.get_historical_klines(market, granularity, '251 days ago UTC') else: raise Exception('Something went wrong!') # convert the API response into a Pandas DataFrame df = pd.DataFrame(resp, columns=[ 'open_time', 'open', 'high', 'low', 'close', 'volume', 'close_time', 'quote_asset_volume', 'number_of_trades', 'taker_buy_base_asset_volume', 'traker_buy_quote_asset_volume', 'ignore' ]) df['market'] = market df['granularity'] = granularity # binance epoch is too long df['open_time'] = df['open_time'] + 1 df['open_time'] = df['open_time'].astype(str) df['open_time'] = df['open_time'].str.replace(r'\d{3}$', '', regex=True) try: freq = FREQUENCY_EQUIVALENTS[SUPPORTED_GRANULARITY.index(granularity)] except: freq = "D" # convert the DataFrame into a time series with the date as the index/key try: tsidx = pd.DatetimeIndex(pd.to_datetime(df['open_time'], unit='s'), dtype='datetime64[ns]', freq=freq) df.set_index(tsidx, inplace=True) df = df.drop(columns=['open_time']) df.index.names = ['ts'] df['date'] = tsidx except ValueError: tsidx = pd.DatetimeIndex(pd.to_datetime(df['open_time'], unit='s'), dtype='datetime64[ns]') df.set_index(tsidx, inplace=True) df = df.drop(columns=['open_time']) df.index.names = ['ts'] df['date'] = tsidx # re-order columns df = df[[ 'date', 'market', 'granularity', 'low', 'high', 'open', 'close', 'volume' ]] # correct column types df['low'] = df['low'].astype(float) df['high'] = df['high'].astype(float) df['open'] = df['open'].astype(float) df['close'] = df['close'].astype(float) df['volume'] = df['volume'].astype(float) # reset pandas dataframe index df.reset_index() return df
def renderSupportResistance(self, saveOnly=False): """Render Support and Resistance Levels Parameters ---------- saveOnly : bool Save the figure without displaying it """ # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity fig, ax = plt.subplots(ncols=1, figsize=(12, 6)) # pylint: disable=unused-variable fig.autofmt_xdate() ax = plt.subplot(111) ax.plot(df.close, label="price", color="black") ax.set_title("Support and Resistance Levels") rotation = 1 last_level = 0 for level in self.levels: # plt.axhline(y=level, color='grey') if last_level != 0: if rotation == 1: ax.axhspan( last_level, level, alpha=0.4, color="lightsalmon", label=str(level), ) elif rotation == 2: ax.axhspan( last_level, level, alpha=0.5, color="palegreen", label=str(level), ) elif rotation == 3: ax.axhspan( last_level, level, alpha=0.5, color="palegoldenrod", label=str(level), ) elif rotation == 4: ax.axhspan( last_level, level, alpha=0.5, color="powderblue", label=str(level), ) else: ax.axhspan(last_level, level, alpha=0.4) last_level = level if rotation < 4: rotation += 1 else: rotation = 1 plt.xlabel(market + " - " + str(granularity)) plt.ylabel("Price") plt.xticks(rotation=90) plt.tight_layout() plt.legend() try: Logger.info( f"creating: graphs/SRL_{market}_{str(granularity)}.png") plt.savefig(f"graphs/SRL_{market}_{str(granularity)}.png", dpi=300) except OSError: raise SystemExit( f"Unable to save: graphs/SRL_{market}_{str(granularity)}.png") if saveOnly is False: plt.show()
def renderCandlesticks(self, period=30, saveOnly=False): # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() if not isinstance(period, int): raise TypeError("Period parameter is not perioderic.") if period < 1 or period > len(df): raise ValueError("Period is out of range") # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity df_subset = df.iloc[-period::] fig, axes = plt.subplots(ncols=1, figsize=(12, 6)) # pylint: disable=unused-variable fig.autofmt_xdate() ax1 = plt.subplot(111) ax1.set_title("Candlestick Patterns") plt.plot(df_subset["close"], label="price", color="black") plt.plot(df_subset["ema12"], label="ema12", color="orange") plt.plot(df_subset["ema26"], label="ema26", color="purple") plt.tick_params(axis="x", which="both", bottom=False, top=False, labelbottom=False) df_candlestick = self.df[self.df["three_white_soldiers"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "g*", markersize=10, label="Three White Soldiers", ) df_candlestick = self.df[self.df["three_black_crows"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "r*", markersize=10, label="Three Black Crows", ) df_candlestick = self.df[self.df["inverted_hammer"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "g*", markersize=10, label="Inverted Hammer", ) df_candlestick = self.df[self.df["hammer"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "g*", markersize=10, label="Hammer", ) df_candlestick = self.df[self.df["hanging_man"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "r*", markersize=10, label="Hanging Man", ) df_candlestick = self.df[self.df["shooting_star"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "r*", markersize=10, label="Shooting Star", ) df_candlestick = self.df[self.df["doji"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "b*", markersize=10, label="Doji", ) df_candlestick = self.df[self.df["three_line_strike"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "g*", markersize=10, label="Three Line Strike", ) df_candlestick = self.df[self.df["two_black_gapping"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "r*", markersize=10, label="Two Black Gapping", ) df_candlestick = self.df[self.df["morning_star"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "g*", markersize=10, label="Morning Star", ) df_candlestick = self.df[self.df["evening_star"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "r*", markersize=10, label="Evening Star", ) df_candlestick = self.df[self.df["morning_doji_star"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "g*", markersize=10, label="Morning Doji Star", ) df_candlestick = self.df[self.df["evening_doji_star"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "r*", markersize=10, label="Evening Doji Star", ) df_candlestick = self.df[self.df["abandoned_baby"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot( idx, df_candlestick_in_range.loc[idx]["close"], "g*", markersize=10, label="Abandoned Baby", ) plt.xlabel(market + " - " + str(granularity)) plt.ylabel("Price") plt.xticks(rotation=90) plt.tight_layout() plt.legend() try: Logger.info( f"creating: graphs/CSP_{market}_{str(granularity)}.png") plt.savefig(f"graphs/CSP_{market}_{str(granularity)}.png", dpi=300) except OSError: raise SystemExit( f"Unable to save: graphs/CSP_{market}_{str(granularity)}.png") if saveOnly is False: plt.show()
def on_message(self, msg): Logger.info(msg)
def on_close(self): Logger.info("-- Websocket Closed --")
def on_open(self): Logger.info("-- Websocket Subscribed! --")
def startApp(self, account, last_action='', banner=True): if banner: Logger.info( '--------------------------------------------------------------------------------' ) Logger.info( '| Python Crypto Bot |' ) Logger.info( '--------------------------------------------------------------------------------' ) txt = ' Release : ' + self.getVersionFromREADME() Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '-----------------------------------------------------------------------------' ) if self.isVerbose(): txt = ' Market : ' + self.getMarket() Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Granularity : ' + str( self.getGranularity()) + ' seconds' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '-----------------------------------------------------------------------------' ) if self.isLive(): txt = ' Bot Mode : LIVE - live trades using your funds!' else: txt = ' Bot Mode : TEST - test trades using dummy funds :)' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Bot Started : ' + str(datetime.now()) Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '================================================================================' ) if self.sellUpperPcnt() != None: txt = ' Sell Upper : ' + str( self.sellUpperPcnt()) + '%' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') if self.sellLowerPcnt() != None: txt = ' Sell Lower : ' + str( self.sellLowerPcnt()) + '%' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') if self.trailingStopLoss() != None: txt = ' Trailing Stop Loss : ' + str( self.trailingStopLoss()) + '%' Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Sell At Loss : ' + str( self.allowSellAtLoss()) + ' --sellatloss ' + str( self.allowSellAtLoss()) Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Sell At Resistance : ' + str( self.sellAtResistance()) + ' --sellatresistance' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Trade Bull Only : ' + str( not self.disableBullOnly()) + ' --disablebullonly' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Buy Near High : ' + str( not self.disableBuyNearHigh()) + ' --disablebuynearhigh' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Use Buy MACD : ' + str( not self.disableBuyMACD()) + ' --disablebuymacd' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Use Buy OBV : ' + str( not self.disableBuyOBV()) + ' --disablebuyobv' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Use Buy Elder-Ray : ' + str( not self.disableBuyElderRay()) + ' --disablebuyelderray' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Sell Fibonacci Low : ' + str( not self.disableFailsafeFibonacciLow() ) + ' --disablefailsafefibonaccilow' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') if self.sellLowerPcnt() != None: txt = ' Sell Lower Pcnt : ' + str( not self.disableFailsafeLowerPcnt() ) + ' --disablefailsafelowerpcnt' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') if self.sellUpperPcnt() != None: txt = ' Sell Upper Pcnt : ' + str( not self.disableFailsafeLowerPcnt() ) + ' --disableprofitbankupperpcnt' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Candlestick Reversal : ' + str( not self.disableProfitbankReversal() ) + ' --disableprofitbankreversal' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Telegram : ' + str( not self.disabletelegram) + ' --disabletelegram' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Log : ' + str( not self.disableLog()) + ' --disablelog' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Tracker : ' + str( not self.disableTracker()) + ' --disabletracker' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Auto restart Bot : ' + str( self.autoRestart()) + ' --autorestart' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') if self.getBuyMaxSize(): txt = ' Max Buy Size : ' + str( self.getBuyMaxSize()) + ' --buymaxsize <size>' Logger.info('| ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '================================================================================' ) # run the first job immediately after starting if self.isSimulation(): if self.simuluationSpeed() in ['fast-sample', 'slow-sample']: tradingData = pd.DataFrame() attempts = 0 if self.simstartdate is not None: date = self.simstartdate.split('-') startDate = datetime(int(date[0]), int(date[1]), int(date[2])) endDate = startDate + timedelta( minutes=(self.getGranularity() / 60) * 300) while len(tradingData) != 300 and attempts < 10: tradingData = self.getHistoricalData( self.getMarket(), self.getGranularity(), startDate.isoformat(timespec='milliseconds')) attempts += 1 elif self.simenddate is not None: if self.simenddate == 'now': endDate = datetime.now() else: date = self.simenddate.split('-') endDate = datetime(int(date[0]), int(date[1]), int(date[2])) startDate = endDate - timedelta( minutes=(self.getGranularity() / 60) * 300) while len(tradingData) != 300 and attempts < 10: tradingData = self.getHistoricalData( self.getMarket(), self.getGranularity(), startDate.isoformat(timespec='milliseconds')) attempts += 1 else: while len(tradingData) != 300 and attempts < 10: endDate = datetime.now() - timedelta( hours=random.randint(0, 8760 * 3)) # 3 years in hours startDate = endDate - timedelta( minutes=(self.getGranularity() / 60) * 300) tradingData = self.getHistoricalData( self.getMarket(), self.getGranularity(), startDate.isoformat(timespec='milliseconds')) attempts += 1 if len(tradingData) != 300: raise Exception( 'Unable to retrieve 300 random sets of data between ' + str(startDate) + ' and ' + str(endDate) + ' in ' + str(attempts) + ' attempts.') if banner: startDate = str(startDate.isoformat()) endDate = str(endDate.isoformat()) txt = ' Sampling start : ' + str(startDate) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Sampling end : ' + str(endDate) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') if self.simstartdate != None: txt = ' WARNING: Using less than 300 intervals' Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Interval size : ' + str(len(tradingData)) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '================================================================================' ) else: tradingData = self.getHistoricalData(self.getMarket(), self.getGranularity()) return tradingData
def executeJob(sc=None, app: PyCryptoBot = None, state: AppState = None, trading_data=pd.DataFrame()): """Trading bot job which runs at a scheduled interval""" global technical_analysis # connectivity check (only when running live) if app.isLive() and app.getTime() is None: Logger.warning( 'Your connection to the exchange has gone down, will retry in 1 minute!' ) # poll every 5 minute list(map(s.cancel, s.queue)) s.enter(300, 1, executeJob, (sc, app, state)) return # increment state.iterations state.iterations = state.iterations + 1 if not app.isSimulation(): # retrieve the app.getMarket() data trading_data = app.getHistoricalData(app.getMarket(), app.getGranularity()) else: if len(trading_data) == 0: return None # analyse the market data if app.isSimulation() and len(trading_data.columns) > 8: df = trading_data # if smartswitch the get the market data using new granularity if app.sim_smartswitch: df_last = app.getInterval(df, state.iterations) if len(df_last.index.format()) > 0: current_df_index = str(df_last.index.format()[0]) current_sim_date = f'{current_df_index} 00:00:00' if len( current_df_index) == 10 else current_df_index dt = current_sim_date.split(' ') date = dt[0].split('-') time = dt[1].split(':') startDate = datetime(int(date[0]), int(date[1]), int(date[2]), int(time[0]), int(time[1]), int(time[2])) trading_data = app.getHistoricalData( app.getMarket(), app.getGranularity(), startDate.isoformat(timespec='milliseconds'), datetime.now().isoformat(timespec='milliseconds')) trading_dataCopy = trading_data.copy() technical_analysis = TechnicalAnalysis(trading_dataCopy) technical_analysis.addAll() df = technical_analysis.getDataFrame() state.iterations = 1 app.sim_smartswitch = False else: trading_dataCopy = trading_data.copy() technical_analysis = TechnicalAnalysis(trading_dataCopy) technical_analysis.addAll() df = technical_analysis.getDataFrame() if app.isSimulation(): df_last = app.getInterval(df, state.iterations) else: df_last = app.getInterval(df) if len(df_last.index.format()) > 0: current_df_index = str(df_last.index.format()[0]) else: current_df_index = state.last_df_index formatted_current_df_index = f'{current_df_index} 00:00:00' if len( current_df_index) == 10 else current_df_index current_sim_date = formatted_current_df_index # use actual sim mode date to check smartchswitch if app.getSmartSwitch() == 1 and app.getGranularity( ) == 3600 and app.is1hEMA1226Bull( current_sim_date) is True and app.is6hEMA1226Bull( current_sim_date) is True: Logger.info( '*** smart switch from granularity 3600 (1 hour) to 900 (15 min) ***' ) if app.isSimulation(): app.sim_smartswitch = True app.notifyTelegram( app.getMarket() + " smart switch from granularity 3600 (1 hour) to 900 (15 min)") app.setGranularity(900) list(map(s.cancel, s.queue)) s.enter(5, 1, executeJob, (sc, app, state)) # use actual sim mode date to check smartchswitch if app.getSmartSwitch() == 1 and app.getGranularity( ) == 900 and app.is1hEMA1226Bull( current_sim_date) is False and app.is6hEMA1226Bull( current_sim_date) is False: Logger.info( "*** smart switch from granularity 900 (15 min) to 3600 (1 hour) ***" ) if app.isSimulation(): app.sim_smartswitch = True app.notifyTelegram( app.getMarket() + " smart switch from granularity 900 (15 min) to 3600 (1 hour)") app.setGranularity(3600) list(map(s.cancel, s.queue)) s.enter(5, 1, executeJob, (sc, app, state)) if app.getExchange() == 'binance' and app.getGranularity() == 86400: if len(df) < 250: # data frame should have 250 rows, if not retry Logger.error('error: data frame length is < 250 (' + str(len(df)) + ')') list(map(s.cancel, s.queue)) s.enter(300, 1, executeJob, (sc, app, state)) else: if len(df) < 300: if not app.isSimulation(): # data frame should have 300 rows, if not retry Logger.error('error: data frame length is < 300 (' + str(len(df)) + ')') list(map(s.cancel, s.queue)) s.enter(300, 1, executeJob, (sc, app, state)) if len(df_last) > 0: now = datetime.today().strftime('%Y-%m-%d %H:%M:%S') # last_action polling if live if app.isLive(): last_action_current = state.last_action state.pollLastAction() if last_action_current != state.last_action: Logger.info( f'last_action change detected from {last_action_current} to {state.last_action}' ) app.notifyTelegram( f"{app.getMarket} last_action change detected from {last_action_current} to {state.last_action}" ) if not app.isSimulation(): ticker = app.getTicker(app.getMarket()) now = ticker[0] price = ticker[1] if price < df_last['low'].values[0] or price == 0: price = float(df_last['close'].values[0]) else: price = float(df_last['close'].values[0]) if price < 0.0001: raise Exception( app.getMarket() + ' is unsuitable for trading, quote price is less than 0.0001!') # technical indicators ema12gtema26 = bool(df_last['ema12gtema26'].values[0]) ema12gtema26co = bool(df_last['ema12gtema26co'].values[0]) goldencross = bool(df_last['goldencross'].values[0]) macdgtsignal = bool(df_last['macdgtsignal'].values[0]) macdgtsignalco = bool(df_last['macdgtsignalco'].values[0]) ema12ltema26 = bool(df_last['ema12ltema26'].values[0]) ema12ltema26co = bool(df_last['ema12ltema26co'].values[0]) macdltsignal = bool(df_last['macdltsignal'].values[0]) macdltsignalco = bool(df_last['macdltsignalco'].values[0]) obv = float(df_last['obv'].values[0]) obv_pc = float(df_last['obv_pc'].values[0]) elder_ray_buy = bool(df_last['eri_buy'].values[0]) elder_ray_sell = bool(df_last['eri_sell'].values[0]) # if simulation, set goldencross based on actual sim date if app.isSimulation(): goldencross = app.is1hSMA50200Bull(current_sim_date) # if simulation interations < 200 set goldencross to true #if app.isSimulation() and state.iterations < 200: # goldencross = True # candlestick detection hammer = bool(df_last['hammer'].values[0]) inverted_hammer = bool(df_last['inverted_hammer'].values[0]) hanging_man = bool(df_last['hanging_man'].values[0]) shooting_star = bool(df_last['shooting_star'].values[0]) three_white_soldiers = bool(df_last['three_white_soldiers'].values[0]) three_black_crows = bool(df_last['three_black_crows'].values[0]) morning_star = bool(df_last['morning_star'].values[0]) evening_star = bool(df_last['evening_star'].values[0]) three_line_strike = bool(df_last['three_line_strike'].values[0]) abandoned_baby = bool(df_last['abandoned_baby'].values[0]) morning_doji_star = bool(df_last['morning_doji_star'].values[0]) evening_doji_star = bool(df_last['evening_doji_star'].values[0]) two_black_gapping = bool(df_last['two_black_gapping'].values[0]) strategy = Strategy(app, state, df, state.iterations) state.action = strategy.getAction() immediate_action = False margin, profit, sell_fee = 0, 0, 0 if state.last_buy_size > 0 and state.last_buy_price > 0 and price > 0 and state.last_action == 'BUY': # update last buy high if price > state.last_buy_high: state.last_buy_high = price if state.last_buy_high > 0: change_pcnt_high = ((price / state.last_buy_high) - 1) * 100 else: change_pcnt_high = 0 # buy and sell calculations state.last_buy_fee = round(state.last_buy_size * app.getTakerFee(), 8) state.last_buy_filled = round( ((state.last_buy_size - state.last_buy_fee) / state.last_buy_price), 8) # if not a simulation, sync with exchange orders if not app.isSimulation(): exchange_last_buy = app.getLastBuy() if exchange_last_buy is not None: if state.last_buy_size != exchange_last_buy['size']: state.last_buy_size = exchange_last_buy['size'] if state.last_buy_filled != exchange_last_buy['filled']: state.last_buy_filled = exchange_last_buy['filled'] if state.last_buy_price != exchange_last_buy['price']: state.last_buy_price = exchange_last_buy['price'] if app.getExchange() == 'coinbasepro': if state.last_buy_fee != exchange_last_buy['fee']: state.last_buy_fee = exchange_last_buy['fee'] margin, profit, sell_fee = calculate_margin( buy_size=state.last_buy_size, buy_filled=state.last_buy_filled, buy_price=state.last_buy_price, buy_fee=state.last_buy_fee, sell_percent=app.getSellPercent(), sell_price=price, sell_taker_fee=app.getTakerFee()) # handle immedate sell actions if strategy.isSellTrigger(price, technical_analysis.getTradeExit(price), margin, change_pcnt_high, obv_pc, macdltsignal): state.action = 'SELL' state.last_action = 'BUY' immediate_action = True # handle overriding wait actions (do not sell if sell at loss disabled!) if strategy.isWaitTrigger(margin): state.action = 'WAIT' state.last_action = 'BUY' immediate_action = False bullbeartext = '' if app.disableBullOnly() is True or (df_last['sma50'].values[0] == df_last['sma200'].values[0]): bullbeartext = '' elif goldencross is True: bullbeartext = ' (BULL)' elif goldencross is False: bullbeartext = ' (BEAR)' # polling is every 5 minutes (even for hourly intervals), but only process once per interval if (immediate_action is True or state.last_df_index != current_df_index): precision = 4 if (price < 0.01): precision = 8 # Since precision does not change after this point, it is safe to prepare a tailored `truncate()` that would # work with this precision. It should save a couple of `precision` uses, one for each `truncate()` call. truncate = functools.partial(_truncate, n=precision) price_text = 'Close: ' + truncate(price) ema_text = '' if app.disableBuyEMA() is False: ema_text = app.compare(df_last['ema12'].values[0], df_last['ema26'].values[0], 'EMA12/26', precision) macd_text = '' if app.disableBuyMACD() is False: macd_text = app.compare(df_last['macd'].values[0], df_last['signal'].values[0], 'MACD', precision) obv_text = '' if app.disableBuyOBV() is False: obv_text = 'OBV: ' + truncate( df_last['obv'].values[0]) + ' (' + str( truncate(df_last['obv_pc'].values[0])) + '%)' state.eri_text = '' if app.disableBuyElderRay() is False: if elder_ray_buy is True: state.eri_text = 'ERI: buy | ' elif elder_ray_sell is True: state.eri_text = 'ERI: sell | ' else: state.eri_text = 'ERI: | ' if hammer is True: log_text = '* Candlestick Detected: Hammer ("Weak - Reversal - Bullish Signal - Up")' Logger.info(log_text) if shooting_star is True: log_text = '* Candlestick Detected: Shooting Star ("Weak - Reversal - Bearish Pattern - Down")' Logger.info(log_text) if hanging_man is True: log_text = '* Candlestick Detected: Hanging Man ("Weak - Continuation - Bearish Pattern - Down")' Logger.info(log_text) if inverted_hammer is True: log_text = '* Candlestick Detected: Inverted Hammer ("Weak - Continuation - Bullish Pattern - Up")' Logger.info(log_text) if three_white_soldiers is True: log_text = '*** Candlestick Detected: Three White Soldiers ("Strong - Reversal - Bullish Pattern - Up")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if three_black_crows is True: log_text = '* Candlestick Detected: Three Black Crows ("Strong - Reversal - Bearish Pattern - Down")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if morning_star is True: log_text = '*** Candlestick Detected: Morning Star ("Strong - Reversal - Bullish Pattern - Up")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if evening_star is True: log_text = '*** Candlestick Detected: Evening Star ("Strong - Reversal - Bearish Pattern - Down")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if three_line_strike is True: log_text = '** Candlestick Detected: Three Line Strike ("Reliable - Reversal - Bullish Pattern - Up")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if abandoned_baby is True: log_text = '** Candlestick Detected: Abandoned Baby ("Reliable - Reversal - Bullish Pattern - Up")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if morning_doji_star is True: log_text = '** Candlestick Detected: Morning Doji Star ("Reliable - Reversal - Bullish Pattern - Up")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if evening_doji_star is True: log_text = '** Candlestick Detected: Evening Doji Star ("Reliable - Reversal - Bearish Pattern - Down")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) if two_black_gapping is True: log_text = '*** Candlestick Detected: Two Black Gapping ("Reliable - Reversal - Bearish Pattern - Down")' Logger.info(log_text) app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') ' + log_text) ema_co_prefix = '' ema_co_suffix = '' if app.disableBuyEMA() is False: if ema12gtema26co is True: ema_co_prefix = '*^ ' ema_co_suffix = ' ^*' elif ema12ltema26co is True: ema_co_prefix = '*v ' ema_co_suffix = ' v*' elif ema12gtema26 is True: ema_co_prefix = '^ ' ema_co_suffix = ' ^' elif ema12ltema26 is True: ema_co_prefix = 'v ' ema_co_suffix = ' v' macd_co_prefix = '' macd_co_suffix = '' if app.disableBuyMACD() is False: if macdgtsignalco is True: macd_co_prefix = '*^ ' macd_co_suffix = ' ^*' elif macdltsignalco is True: macd_co_prefix = '*v ' macd_co_suffix = ' v*' elif macdgtsignal is True: macd_co_prefix = '^ ' macd_co_suffix = ' ^' elif macdltsignal is True: macd_co_prefix = 'v ' macd_co_suffix = ' v' obv_prefix = '' obv_suffix = '' if app.disableBuyOBV() is False: if float(obv_pc) > 0: obv_prefix = '^ ' obv_suffix = ' ^ | ' elif float(obv_pc) < 0: obv_prefix = 'v ' obv_suffix = ' v | ' if not app.isVerbose(): if state.last_action != '': output_text = formatted_current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + \ app.printGranularity() + ' | ' + price_text + ' | ' + ema_co_prefix + \ ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + \ obv_prefix + obv_text + obv_suffix + state.eri_text + ' | ' + state.action + \ ' | Last Action: ' + state.last_action else: output_text = formatted_current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + \ app.printGranularity() + ' | ' + price_text + ' | ' + ema_co_prefix + \ ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + \ obv_prefix + obv_text + obv_suffix + state.eri_text + ' | ' + state.action + ' ' if state.last_action == 'BUY': if state.last_buy_size > 0: margin_text = truncate(margin) + '%' else: margin_text = '0%' output_text += ' | ' + margin_text + ' (delta: ' + str( round(price - state.last_buy_price, precision)) + ')' Logger.info(output_text) # Seasonal Autoregressive Integrated Moving Average (ARIMA) model (ML prediction for 3 intervals from now) if not app.isSimulation(): try: prediction = technical_analysis.seasonalARIMAModelPrediction( int(app.getGranularity() / 60) * 3) # 3 intervals from now Logger.info( f'Seasonal ARIMA model predicts the closing price will be {str(round(prediction[1], 2))} at {prediction[0]} (delta: {round(prediction[1] - price, 2)})' ) except: pass if state.last_action == 'BUY': # display support, resistance and fibonacci levels Logger.info( technical_analysis. printSupportResistanceFibonacciLevels(price)) else: Logger.debug('-- Iteration: ' + str(state.iterations) + ' --' + bullbeartext) if state.last_action == 'BUY': if state.last_buy_size > 0: margin_text = truncate(margin) + '%' else: margin_text = '0%' Logger.debug('-- Margin: ' + margin_text + ' --') Logger.debug('price: ' + truncate(price)) Logger.debug('ema12: ' + truncate(float(df_last['ema12'].values[0]))) Logger.debug('ema26: ' + truncate(float(df_last['ema26'].values[0]))) Logger.debug('ema12gtema26co: ' + str(ema12gtema26co)) Logger.debug('ema12gtema26: ' + str(ema12gtema26)) Logger.debug('ema12ltema26co: ' + str(ema12ltema26co)) Logger.debug('ema12ltema26: ' + str(ema12ltema26)) Logger.debug('sma50: ' + truncate(float(df_last['sma50'].values[0]))) Logger.debug('sma200: ' + truncate(float(df_last['sma200'].values[0]))) Logger.debug('macd: ' + truncate(float(df_last['macd'].values[0]))) Logger.debug('signal: ' + truncate(float(df_last['signal'].values[0]))) Logger.debug('macdgtsignal: ' + str(macdgtsignal)) Logger.debug('macdltsignal: ' + str(macdltsignal)) Logger.debug('obv: ' + str(obv)) Logger.debug('obv_pc: ' + str(obv_pc)) Logger.debug('action: ' + state.action) # informational output on the most recent entry Logger.info('') Logger.info( '================================================================================' ) txt = ' Iteration : ' + str( state.iterations) + bullbeartext Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Timestamp : ' + str(df_last.index.format()[0]) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '--------------------------------------------------------------------------------' ) txt = ' Close : ' + truncate(price) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' EMA12 : ' + truncate( float(df_last['ema12'].values[0])) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' EMA26 : ' + truncate( float(df_last['ema26'].values[0])) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Crossing Above : ' + str(ema12gtema26co) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Currently Above : ' + str(ema12gtema26) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Crossing Below : ' + str(ema12ltema26co) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Currently Below : ' + str(ema12ltema26) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') if (ema12gtema26 is True and ema12gtema26co is True): txt = ' Condition : EMA12 is currently crossing above EMA26' elif (ema12gtema26 is True and ema12gtema26co is False): txt = ' Condition : EMA12 is currently above EMA26 and has crossed over' elif (ema12ltema26 is True and ema12ltema26co is True): txt = ' Condition : EMA12 is currently crossing below EMA26' elif (ema12ltema26 is True and ema12ltema26co is False): txt = ' Condition : EMA12 is currently below EMA26 and has crossed over' else: txt = ' Condition : -' Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' SMA20 : ' + truncate( float(df_last['sma20'].values[0])) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' SMA200 : ' + truncate( float(df_last['sma200'].values[0])) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '--------------------------------------------------------------------------------' ) txt = ' MACD : ' + truncate( float(df_last['macd'].values[0])) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Signal : ' + truncate( float(df_last['signal'].values[0])) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Currently Above : ' + str(macdgtsignal) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') txt = ' Currently Below : ' + str(macdltsignal) Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') if (macdgtsignal is True and macdgtsignalco is True): txt = ' Condition : MACD is currently crossing above Signal' elif (macdgtsignal is True and macdgtsignalco is False): txt = ' Condition : MACD is currently above Signal and has crossed over' elif (macdltsignal is True and macdltsignalco is True): txt = ' Condition : MACD is currently crossing below Signal' elif (macdltsignal is True and macdltsignalco is False): txt = ' Condition : MACD is currently below Signal and has crossed over' else: txt = ' Condition : -' Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '--------------------------------------------------------------------------------' ) txt = ' Action : ' + state.action Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '================================================================================' ) if state.last_action == 'BUY': txt = ' Margin : ' + margin_text Logger.info(' | ' + txt + (' ' * (75 - len(txt))) + ' | ') Logger.info( '================================================================================' ) # if a buy signal if state.action == 'BUY': state.last_buy_price = price state.last_buy_high = state.last_buy_price # if live if app.isLive(): app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') BUY at ' + price_text) if not app.isVerbose(): Logger.info(formatted_current_df_index + ' | ' + app.getMarket() + ' | ' + app.printGranularity() + ' | ' + price_text + ' | BUY') else: Logger.info( '--------------------------------------------------------------------------------' ) Logger.info( '| *** Executing LIVE Buy Order *** |' ) Logger.info( '--------------------------------------------------------------------------------' ) # display balances Logger.info(app.getBaseCurrency() + ' balance before order: ' + str(account.getBalance(app.getBaseCurrency()))) Logger.info( app.getQuoteCurrency() + ' balance before order: ' + str(account.getBalance(app.getQuoteCurrency()))) # execute a live market buy state.last_buy_size = float( account.getBalance(app.getQuoteCurrency())) if app.getBuyMaxSize( ) and state.last_buy_size > app.getBuyMaxSize(): state.last_buy_size = app.getBuyMaxSize() resp = app.marketBuy(app.getMarket(), state.last_buy_size, app.getBuyPercent()) Logger.debug(resp) # display balances Logger.info(app.getBaseCurrency() + ' balance after order: ' + str(account.getBalance(app.getBaseCurrency()))) Logger.info( app.getQuoteCurrency() + ' balance after order: ' + str(account.getBalance(app.getQuoteCurrency()))) # if not live else: app.notifyTelegram(app.getMarket() + ' (' + app.printGranularity() + ') TEST BUY at ' + price_text) # TODO: Improve simulator calculations by including calculations for buy and sell limit configurations. if state.last_buy_size == 0 and state.last_buy_filled == 0: state.last_buy_size = 1000 state.first_buy_size = 1000 state.buy_count = state.buy_count + 1 state.buy_sum = state.buy_sum + state.last_buy_size if not app.isVerbose(): Logger.info(formatted_current_df_index + ' | ' + app.getMarket() + ' | ' + app.printGranularity() + ' | ' + price_text + ' | BUY') bands = technical_analysis.getFibonacciRetracementLevels( float(price)) Logger.info(' Fibonacci Retracement Levels:' + str(bands)) technical_analysis.printSupportResistanceLevel( float(price)) if len(bands) >= 1 and len(bands) <= 2: if len(bands) == 1: first_key = list(bands.keys())[0] if first_key == 'ratio1': state.fib_low = 0 state.fib_high = bands[first_key] if first_key == 'ratio1_618': state.fib_low = bands[first_key] state.fib_high = bands[first_key] * 2 else: state.fib_low = bands[first_key] elif len(bands) == 2: first_key = list(bands.keys())[0] second_key = list(bands.keys())[1] state.fib_low = bands[first_key] state.fib_high = bands[second_key] else: Logger.info( '--------------------------------------------------------------------------------' ) Logger.info( '| *** Executing TEST Buy Order *** |' ) Logger.info( '--------------------------------------------------------------------------------' ) if app.shouldSaveGraphs(): tradinggraphs = TradingGraphs(technical_analysis) ts = datetime.now().timestamp() filename = app.getMarket() + '_' + app.printGranularity( ) + '_buy_' + str(ts) + '.png' tradinggraphs.renderEMAandMACD(len(trading_data), 'graphs/' + filename, True) # if a sell signal elif state.action == 'SELL': # if live if app.isLive(): app.notifyTelegram( app.getMarket() + ' (' + app.printGranularity() + ') SELL at ' + price_text + ' (margin: ' + margin_text + ', (delta: ' + str(round(price - state.last_buy_price, precision)) + ')') if not app.isVerbose(): Logger.info(formatted_current_df_index + ' | ' + app.getMarket() + ' | ' + app.printGranularity() + ' | ' + price_text + ' | SELL') bands = technical_analysis.getFibonacciRetracementLevels( float(price)) Logger.info(' Fibonacci Retracement Levels:' + str(bands)) if len(bands) >= 1 and len(bands) <= 2: if len(bands) == 1: first_key = list(bands.keys())[0] if first_key == 'ratio1': state.fib_low = 0 state.fib_high = bands[first_key] if first_key == 'ratio1_618': state.fib_low = bands[first_key] state.fib_high = bands[first_key] * 2 else: state.fib_low = bands[first_key] elif len(bands) == 2: first_key = list(bands.keys())[0] second_key = list(bands.keys())[1] state.fib_low = bands[first_key] state.fib_high = bands[second_key] else: Logger.info( '--------------------------------------------------------------------------------' ) Logger.info( '| *** Executing LIVE Sell Order *** |' ) Logger.info( '--------------------------------------------------------------------------------' ) # display balances Logger.info(app.getBaseCurrency() + ' balance before order: ' + str(account.getBalance(app.getBaseCurrency()))) Logger.info( app.getQuoteCurrency() + ' balance before order: ' + str(account.getBalance(app.getQuoteCurrency()))) # execute a live market sell resp = app.marketSell( app.getMarket(), float(account.getBalance(app.getBaseCurrency())), app.getSellPercent()) Logger.debug(resp) # display balances Logger.info(app.getBaseCurrency() + ' balance after order: ' + str(account.getBalance(app.getBaseCurrency()))) Logger.info( app.getQuoteCurrency() + ' balance after order: ' + str(account.getBalance(app.getQuoteCurrency()))) # if not live else: margin, profit, sell_fee = calculate_margin( buy_size=state.last_buy_size, buy_filled=state.last_buy_filled, buy_price=state.last_buy_price, buy_fee=state.last_buy_fee, sell_percent=app.getSellPercent(), sell_price=price, sell_taker_fee=app.getTakerFee()) if state.last_buy_size > 0: margin_text = truncate(margin) + '%' else: margin_text = '0%' app.notifyTelegram( app.getMarket() + ' (' + app.printGranularity() + ') TEST SELL at ' + price_text + ' (margin: ' + margin_text + ', (delta: ' + str(round(price - state.last_buy_price, precision)) + ')') # Preserve next buy values for simulator state.sell_count = state.sell_count + 1 buy_size = ((app.getSellPercent() / 100) * ((price / state.last_buy_price) * (state.last_buy_size - state.last_buy_fee))) state.last_buy_size = buy_size - sell_fee state.sell_sum = state.sell_sum + state.last_buy_size if not app.isVerbose(): if price > 0: margin_text = truncate(margin) + '%' else: margin_text = '0%' Logger.info(formatted_current_df_index + ' | ' + app.getMarket() + ' | ' + app.printGranularity() + ' | SELL | ' + str(price) + ' | BUY | ' + str(state.last_buy_price) + ' | DIFF | ' + str(price - state.last_buy_price) + ' | DIFF | ' + str(profit) + ' | MARGIN NO FEES | ' + margin_text + ' | MARGIN FEES | ' + str(round(sell_fee, precision))) else: Logger.info( '--------------------------------------------------------------------------------' ) Logger.info( '| *** Executing TEST Sell Order *** |' ) Logger.info( '--------------------------------------------------------------------------------' ) if app.shouldSaveGraphs(): tradinggraphs = TradingGraphs(technical_analysis) ts = datetime.now().timestamp() filename = app.getMarket() + '_' + app.printGranularity( ) + '_sell_' + str(ts) + '.png' tradinggraphs.renderEMAandMACD(len(trading_data), 'graphs/' + filename, True) # last significant action if state.action in ['BUY', 'SELL']: state.last_action = state.action state.last_df_index = str(df_last.index.format()[0]) if not app.isLive() and state.iterations == len(df): Logger.info("\nSimulation Summary: ") if state.buy_count > state.sell_count and app.allowSellAtLoss( ): # Calculate last sell size state.last_buy_size = ((app.getSellPercent() / 100) * ( (price / state.last_buy_price) * (state.last_buy_size - state.last_buy_fee))) # Reduce sell fee from last sell size state.last_buy_size = state.last_buy_size - state.last_buy_price * app.getTakerFee( ) state.sell_sum = state.sell_sum + state.last_buy_size state.sell_count = state.sell_count + 1 elif state.buy_count > state.sell_count and not app.allowSellAtLoss( ): Logger.info("\n") Logger.info( ' Note : "sell at loss" is disabled and you have an open trade, if the margin' ) Logger.info( ' result below is negative it will assume you sold at the end of the' ) Logger.info( ' simulation which may not be ideal. Try setting --sellatloss 1' ) Logger.info("\n") Logger.info(' Buy Count : ' + str(state.buy_count)) Logger.info(' Sell Count : ' + str(state.sell_count)) Logger.info(' First Buy : ' + str(state.first_buy_size)) Logger.info(' Last Sell : ' + str(state.last_buy_size)) app.notifyTelegram( f"Simulation Summary\n Buy Count: {state.buy_count}\n Sell Count: {state.sell_count}\n First Buy: {state.first_buy_size}\n Last Sell: {state.last_buy_size}\n" ) if state.sell_count > 0: Logger.info("\n") Logger.info(' Margin : ' + _truncate(( ((state.last_buy_size - state.first_buy_size) / state.first_buy_size) * 100), 4) + '%') Logger.info("\n") Logger.info( ' ** non-live simulation, assuming highest fees') app.notifyTelegram( f" Margin: {_truncate((((state.last_buy_size - state.first_buy_size) / state.first_buy_size) * 100), 4)}%\n ** non-live simulation, assuming highest fees\n" ) else: if state.last_buy_size > 0 and state.last_buy_price > 0 and price > 0 and state.last_action == 'BUY': # show profit and margin if already bought Logger.info(now + ' | ' + app.getMarket() + bullbeartext + ' | ' + app.printGranularity() + ' | Current Price: ' + str(price) + ' | Margin: ' + str(margin) + ' | Profit: ' + str(profit)) else: Logger.info(now + ' | ' + app.getMarket() + bullbeartext + ' | ' + app.printGranularity() + ' | Current Price: ' + str(price)) # decrement ignored iteration state.iterations = state.iterations - 1 # if live if not app.disableTracker() and app.isLive(): # update order tracker csv if app.getExchange() == 'binance': account.saveTrackerCSV(app.getMarket()) elif app.getExchange() == 'coinbasepro': account.saveTrackerCSV() if app.isSimulation(): if state.iterations < 300: if app.simuluationSpeed() in ['fast', 'fast-sample']: # fast processing list(map(s.cancel, s.queue)) s.enter(0, 1, executeJob, (sc, app, state, df)) else: # slow processing list(map(s.cancel, s.queue)) s.enter(1, 1, executeJob, (sc, app, state, df)) else: # poll every 1 minute list(map(s.cancel, s.queue)) s.enter(60, 1, executeJob, (sc, app, state))
def renderSeasonalARIMAModelPrediction(self, days=30, saveOnly=False): """Render the seasonal ARIMA model prediction Parameters ---------- days : int Number of days to predict saveOnly : bool Save the figure without displaying it """ # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() if not isinstance(days, int): raise TypeError("Prediction days is not numeric.") if days < 1 or days > len(df): raise ValueError("Predication days is out of range") # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity results_ARIMA = self.technical_analysis.seasonalARIMAModel() df = pd.DataFrame(self.df["close"]) start_date = df.last_valid_index() end_date = start_date + datetime.timedelta(days=days) pred = results_ARIMA.predict(start=str(start_date), end=str(end_date), dynamic=True) fig, axes = plt.subplots(ncols=1, figsize=(12, 6)) # pylint: disable=unused-variable fig.autofmt_xdate() ax1 = plt.subplot(111) ax1.set_title("Seasonal ARIMA Model Prediction") date = pd.to_datetime(pred.index).to_pydatetime() pred_length = len(pred) # the evenly spaced plot indices indices = np.arange(pred_length) # pylint: disable=unused-variable def format_date(x, pos=None): # pylint: disable=unused-argument thisind = np.clip(int(x + 0.5), 0, pred_length - 1) return date[thisind].strftime("%Y-%m-%d %H:%M:%S") fig, ax = plt.subplots(ncols=1, figsize=(12, 6)) # pylint: disable=unused-variable fig.autofmt_xdate() ax = plt.subplot(111) ax.set_title("Seasonal ARIMA Model Prediction") ax.plot(pred, label="prediction", color="black") ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) plt.xticks(rotation=90) plt.tight_layout() try: Logger.info( f"creating: graphs/SAM_{market}_{str(granularity)}.png") plt.savefig(f"graphs/SAM_{market}_{str(granularity)}.png", dpi=300) except OSError: raise SystemExit( f"Unable to save: graphs/SAM_{market}_{str(granularity)}.png") if saveOnly is False: plt.show()
def show(self): if self.app.getStats(): # get completed live orders self.app.setLive(1) self.orders = self.account.getOrders(self.app.getMarket(), '', 'done') # get buy/sell pairs (merge as necessary) order_pairs = [] last_order = None # pylint: disable=unused-variable for index, row in self.orders.iterrows(): time = row['created_at'].to_pydatetime() if row['action'] == 'buy': if last_order in ['sell', None]: last_order = 'buy' order_pairs.append({ 'buy': { 'time': time, 'size': row['size'] }, 'sell': None }) else: last_order = 'buy' order_pairs[-1]['buy']['size'] += row['size'] else: if last_order == None: # first order is a sell (no pair) continue if last_order == 'buy': last_order = 'sell' order_pairs[-1]['sell'] = { 'time': time, 'size': row['size'] } else: order_pairs[-1]['sell']['size'] += row['size'] # remove open trade if len(order_pairs) > 0: if order_pairs[-1]['sell'] == None: order_pairs = order_pairs[:-1] # get % gains and delta for pair in order_pairs: pair['gain'] = ((pair['sell']['size'] - pair['buy']['size']) / pair['buy']['size']) * 100 pair['delta'] = pair['sell']['size'] - pair['buy']['size'] # get day/week/month/all time totals totals = {'today': [], 'week': [], 'month': [], 'all_time': []} today = datetime.today().date() lastweek = today - timedelta(days=7) lastmonth = today - timedelta(days=30) for pair in order_pairs: totals['all_time'].append(pair) if pair['sell']['time'].date() == today: totals['today'].append(pair) if pair['sell']['time'].date() > lastweek: totals['week'].append(pair) if pair['sell']['time'].date() > lastmonth: totals['month'].append(pair) # prepare data for output today_per = [x['gain'] for x in totals['today']] week_per = [x['gain'] for x in totals['week']] month_per = [x['gain'] for x in totals['month']] all_time_per = [x['gain'] for x in totals['all_time']] today_gain = [x['delta'] for x in totals['today']] week_gain = [x['delta'] for x in totals['week']] month_gain = [x['delta'] for x in totals['month']] all_time_gain = [x['delta'] for x in totals['all_time']] if len(today_per) > 0: today_delta = [ (x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['today'] ] today_delta = timedelta( seconds=int(sum(today_delta) / len(today_delta))) else: today_delta = '0:0:0' if len(week_per) > 0: week_delta = [ (x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['week'] ] week_delta = timedelta( seconds=int(sum(week_delta) / len(week_delta))) else: week_delta = '0:0:0' if len(month_per) > 0: month_delta = [ (x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['month'] ] month_delta = timedelta( seconds=int(sum(month_delta) / len(month_delta))) else: month_delta = '0:0:0' if len(all_time_per) > 0: all_time_delta = [ (x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['all_time'] ] all_time_delta = timedelta( seconds=int(sum(all_time_delta) / len(all_time_delta))) else: all_time_delta = '0:0:0' # popular currencies symbol = self.app.getQuoteCurrency() if symbol in ['USD', 'AUD', 'CAD', 'SGD', 'NZD']: symbol = '$' if symbol == 'EUR': symbol = '€' if symbol == 'GBP': symbol = '£' today_sum = symbol + ' {:.2f}'.format(round(sum( today_gain), 2)) if len(today_gain) > 0 else symbol + ' 0.00' week_sum = symbol + ' {:.2f}'.format(round( sum(week_gain), 2)) if len(week_gain) > 0 else symbol + ' 0.00' month_sum = symbol + ' {:.2f}'.format(round(sum( month_gain), 2)) if len(month_gain) > 0 else symbol + ' 0.00' all_time_sum = symbol + ' {:.2f}'.format( round(sum(all_time_gain), 2)) if len(all_time_gain) > 0 else symbol + ' 0.00' today_percent = str(round( sum(today_per), 4)) + '%' if len(today_per) > 0 else '0.0000%' week_percent = str(round( sum(week_per), 4)) + '%' if len(week_per) > 0 else '0.0000%' month_percent = str(round( sum(month_per), 4)) + '%' if len(month_per) > 0 else '0.0000%' all_time_percent = str(round(sum(all_time_per), 4)) + '%' if len( all_time_per) > 0 else '0.0000%' trades = 'Number of Completed Trades:' gains = 'Percentage Gains:' aver = 'Average Time Held (H:M:S):' success = 'Total Profit/Loss:' width = 30 Logger.info( f'------------- TODAY : {self.app.getMarket()} --------------') Logger.info(trades + ' ' * (width - len(trades)) + str(len(today_per))) Logger.info(gains + ' ' * (width - len(gains)) + today_percent) Logger.info(aver + ' ' * (width - len(aver)) + str(today_delta)) Logger.info(success + ' ' * (width - len(success)) + today_sum) Logger.info( f'\n-------------- WEEK : {self.app.getMarket()} --------------' ) Logger.info(trades + ' ' * (width - len(trades)) + str(len(week_per))) Logger.info(gains + ' ' * (width - len(gains)) + week_percent) Logger.info(aver + ' ' * (width - len(aver)) + str(week_delta)) Logger.info(success + ' ' * (width - len(success)) + week_sum) Logger.info( f'\n------------- MONTH : {self.app.getMarket()} --------------' ) Logger.info(trades + ' ' * (width - len(trades)) + str(len(month_per))) Logger.info(gains + ' ' * (width - len(gains)) + month_percent) Logger.info(aver + ' ' * (width - len(aver)) + str(month_delta)) Logger.info(success + ' ' * (width - len(success)) + month_sum) Logger.info( f'\n------------ ALL TIME : {self.app.getMarket()} ------------' ) Logger.info(trades + ' ' * (width - len(trades)) + str(len(all_time_per))) Logger.info(gains + ' ' * (width - len(gains)) + all_time_percent) Logger.info(aver + ' ' * (width - len(aver)) + str(all_time_delta)) Logger.info(success + ' ' * (width - len(success)) + all_time_sum) sys.exit()
def renderCandlestickAstralPattern(self, period=30, saveOnly=False): # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() if not isinstance(period, int): raise TypeError("Period parameter is not perioderic.") if period < 1 or period > len(df): raise ValueError("Period is out of range") # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity df_subset = df.iloc[-period::] fig, axes = plt.subplots(ncols=1, figsize=(12, 6)) # pylint: disable=unused-variable fig.autofmt_xdate() ax1 = plt.subplot(111) ax1.set_title("Astral Candlestick Pattern") plt.plot(df_subset["close"], label="price", color="black") plt.plot(df_subset["ema12"], label="ema12", color="orange") plt.plot(df_subset["ema26"], label="ema26", color="purple") plt.tick_params(axis="x", which="both", bottom=False, top=False, labelbottom=False) df_candlestick = self.df[self.df["astral_buy"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]["close"], "g^", markersize=8) df_candlestick = self.df[self.df["astral_sell"] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]["close"], "rv", markersize=8) plt.xlabel(market + " - " + str(granularity)) plt.ylabel("Price") plt.xticks(rotation=90) plt.tight_layout() plt.legend() try: Logger.info( f"creating: graphs/CAP_{market}_{str(granularity)}.png") plt.savefig(f"graphs/CAP_{market}_{str(granularity)}.png", dpi=300) except OSError: raise SystemExit( f"Unable to save: graphs/CAP_{market}_{str(granularity)}.png") if saveOnly is False: plt.show()
def renderCandlesticks(self, period=30, saveOnly=False): # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() if not isinstance(period, int): raise TypeError('Period parameter is not perioderic.') if period < 1 or period > len(df): raise ValueError('Period is out of range') # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity df_subset = df.iloc[-period::] fig, axes = plt.subplots(ncols=1, figsize=(12, 6)) #pylint: disable=unused-variable fig.autofmt_xdate() ax1 = plt.subplot(111) ax1.set_title('Candlestick Patterns') plt.plot(df_subset['close'], label='price', color='black') plt.plot(df_subset['ema12'], label='ema12', color='orange') plt.plot(df_subset['ema26'], label='ema26', color='purple') plt.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False) df_candlestick = self.df[self.df['three_white_soldiers'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g*', markersize=10, label='Three White Soldiers') df_candlestick = self.df[self.df['three_black_crows'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'r*', markersize=10, label='Three Black Crows') df_candlestick = self.df[self.df['inverted_hammer'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g*', markersize=10, label='Inverted Hammer') df_candlestick = self.df[self.df['hammer'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g*', markersize=10, label='Hammer') df_candlestick = self.df[self.df['hanging_man'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'r*', markersize=10, label='Hanging Man') df_candlestick = self.df[self.df['shooting_star'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'r*', markersize=10, label='Shooting Star') df_candlestick = self.df[self.df['doji'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'b*', markersize=10, label='Doji') df_candlestick = self.df[self.df['three_line_strike'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g*', markersize=10, label='Three Line Strike') df_candlestick = self.df[self.df['two_black_gapping'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'r*', markersize=10, label='Two Black Gapping') df_candlestick = self.df[self.df['morning_star'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g*', markersize=10, label='Morning Star') df_candlestick = self.df[self.df['evening_star'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'r*', markersize=10, label='Evening Star') df_candlestick = self.df[self.df['morning_doji_star'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g*', markersize=10, label='Morning Doji Star') df_candlestick = self.df[self.df['evening_doji_star'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'r*', markersize=10, label='Evening Doji Star') df_candlestick = self.df[self.df['abandoned_baby'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g*', markersize=10, label='Abandoned Baby') plt.xlabel(market + ' - ' + str(granularity)) plt.ylabel('Price') plt.xticks(rotation=90) plt.tight_layout() plt.legend() try: Logger.info('creating: graphs/CSP_' + market + '_' + str(granularity) + '.png') plt.savefig('graphs/CSP_' + market + '_' + str(granularity) + '.png', dpi=300) except OSError: raise SystemExit('Unable to save: graphs/CSP_' + market + '_' + str(granularity) + '.png') if saveOnly is False: plt.show()
def renderFibonacciRetracement(self, saveOnly=False): """Render Fibonacci Retracement Levels Parameters ---------- saveOnly : bool Save the figure without displaying it """ # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity # closing price min and max values price_min = df.close.min() price_max = df.close.max() # fibonacci retracement levels diff = price_max - price_min level1 = price_max - 0.236 * diff level2 = price_max - 0.382 * diff level3 = price_max - 0.618 * diff fig, ax = plt.subplots(ncols=1, figsize=(12, 6)) # pylint: disable=unused-variable fig.autofmt_xdate() ax = plt.subplot(111) ax.plot(df.close, label="price", color="black") ax.set_title("Fibonacci Retracement Levels") ax.axhspan(level1, price_min, alpha=0.4, color="lightsalmon", label="0.618") ax.axhspan(level3, level2, alpha=0.5, color="palegreen", label="0.382") ax.axhspan(level2, level1, alpha=0.5, color="palegoldenrod", label="0.236") ax.axhspan(price_max, level3, alpha=0.5, color="powderblue", label="0") plt.xlabel(market + " - " + str(granularity)) plt.ylabel("Price") plt.xticks(rotation=90) plt.tight_layout() plt.legend() try: Logger.info( f"creating: graphs/FRL_{market}_{str(granularity)}.png") plt.savefig(f"graphs/FRL_{market}_{str(granularity)}.png", dpi=300) except OSError: raise SystemExit( f"Unable to save: graphs/FRL_{market}_{str(granularity)}.png") if saveOnly is False: plt.show()
def data_display(self): # get % gains and delta for pair in self.order_pairs: pair['delta'] = pair['sell']['size'] - pair['buy']['size'] pair['gain'] = (pair['delta'] / pair['buy']['size']) * 100 # get day/week/month/all time totals totals = {'today': [], 'week': [], 'month': [], 'all_time': []} today = datetime.today().date() lastweek = today - timedelta(days=7) lastmonth = today - timedelta(days=30) if self.app.statstartdate: try: start = datetime.strptime(self.app.statstartdate, '%Y-%m-%d').date() except: raise ValueError("format of --statstartdate must be yyyy-mm-dd") else: start = None # popular currencies symbol = self.app.getQuoteCurrency() if symbol in ['USD', 'AUD', 'CAD', 'SGD', 'NZD']: symbol = '$' if symbol == 'EUR': symbol = '€' if symbol == 'GBP': symbol = '£' if self.app.statdetail: headers = ["| Num ", "| Market ", "| Date of Sell ", "| Price bought ", "| Price sold ", "| Delta ", "| Gain/Loss |"] border = "+" for header in headers: border += "-" * (len(header) - 1) + '+' border = border[:-2] + '+' Logger.info(border + "\n" + "".join([x for x in headers]) + "\n" + border) for i, pair in enumerate(self.order_pairs): if start: if pair['sell']['time'].date() < start: continue d_num = '| ' + str(i + 1) d_num = d_num + ' ' * (len(headers[0]) - len(d_num)) d_date = '| ' + str(pair['sell']['time'].date()) d_market = '| ' + pair['market'] d_market = d_market + ' ' * (len(headers[1]) - len(d_market)) d_date = d_date + ' ' * (len(headers[2]) - len(d_date)) d_buy_size = '| ' + symbol + ' ' + '{:.2f}'.format(pair['buy']['size']) d_buy_size = d_buy_size + ' ' * (len(headers[3]) - len(d_buy_size)) d_sell_size = '| ' + symbol + ' ' + '{:.2f}'.format(pair['sell']['size']) d_sell_size = d_sell_size + ' ' * (len(headers[4]) - len(d_sell_size)) if pair['delta'] > 0: d_delta = '| ' + symbol + ' {:.2f}'.format(pair['delta']) else: d_delta = '| ' + symbol + '{:.2f}'.format(pair['delta']) d_delta = d_delta + ' ' * (len(headers[5]) - len(d_delta)) if pair['gain'] > 0: d_gain = '| ' + '{:.2f}'.format(pair['gain']) + ' %' else: d_gain = '| ' + '{:.2f}'.format(pair['gain']) + ' %' d_gain = d_gain + ' ' * (len(headers[6]) - len(d_gain) -1) + '|' Logger.info(d_num + d_market + d_date + d_buy_size + d_sell_size + d_delta + d_gain) Logger.info(border) sys.exit() for pair in self.order_pairs: if start: if pair['sell']['time'].date() < start: continue totals['all_time'].append(pair) if pair['sell']['time'].date() == today: totals['today'].append(pair) if pair['sell']['time'].date() > lastweek: totals['week'].append(pair) if pair['sell']['time'].date() > lastmonth: totals['month'].append(pair) # prepare data for output today_per = [x['gain'] for x in totals['today']] week_per = [x['gain'] for x in totals['week']] month_per = [x['gain'] for x in totals['month']] all_time_per = [x['gain'] for x in totals['all_time']] today_gain = [x['delta'] for x in totals['today']] week_gain = [x['delta'] for x in totals['week']] month_gain = [x['delta'] for x in totals['month']] all_time_gain = [x['delta'] for x in totals['all_time']] if len(today_per) > 0: today_delta = [(x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['today']] today_delta = timedelta(seconds=int(sum(today_delta) / len(today_delta))) else: today_delta = '0:0:0' if len(week_per) > 0: week_delta = [(x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['week']] week_delta = timedelta(seconds=int(sum(week_delta) / len(week_delta))) else: week_delta = '0:0:0' if len(month_per) > 0: month_delta = [(x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['month']] month_delta = timedelta(seconds=int(sum(month_delta) / len(month_delta))) else: month_delta = '0:0:0' if len(all_time_per) > 0: all_time_delta = [(x['sell']['time'] - x['buy']['time']).total_seconds() for x in totals['all_time']] all_time_delta = timedelta(seconds=int(sum(all_time_delta) / len(all_time_delta))) else: all_time_delta = '0:0:0' today_sum = symbol + ' {:.2f}'.format(round(sum(today_gain), 2)) if len(today_gain) > 0 else symbol + ' 0.00' week_sum = symbol + ' {:.2f}'.format(round(sum(week_gain), 2)) if len(week_gain) > 0 else symbol + ' 0.00' month_sum= symbol + ' {:.2f}'.format(round(sum(month_gain), 2)) if len(month_gain) > 0 else symbol + ' 0.00' all_time_sum = symbol + ' {:.2f}'.format(round(sum(all_time_gain), 2)) if len(all_time_gain) > 0 else symbol + ' 0.00' today_percent = str(round(sum(today_per), 4)) + '%' if len(today_per) > 0 else '0.0000%' week_percent = str(round(sum(week_per), 4)) + '%' if len(week_per) > 0 else '0.0000%' month_percent = str(round(sum(month_per), 4)) + '%' if len(month_per) > 0 else '0.0000%' all_time_percent = str(round(sum(all_time_per), 4)) + '%' if len(all_time_per) > 0 else '0.0000%' trades = 'Number of Completed Trades:' gains = 'Percentage Gains:' aver = 'Average Time Held (H:M:S):' success = 'Total Profit/Loss:' width = 30 if self.app.statgroup: header = 'MERGE' else: header = self.app.getMarket() Logger.info(f'------------- TODAY : {header} --------------') Logger.info(trades + ' ' * (width-len(trades)) + str(len(today_per))) Logger.info(gains + ' ' * (width-len(gains)) + today_percent) Logger.info(aver + ' ' * (width-len(aver)) + str(today_delta)) Logger.info(success + ' ' * (width-len(success)) + today_sum) Logger.info(f'\n-------------- WEEK : {header} --------------') Logger.info(trades + ' ' * (width-len(trades)) + str(len(week_per))) Logger.info(gains + ' ' * (width-len(gains)) + week_percent) Logger.info(aver + ' ' * (width-len(aver)) + str(week_delta)) Logger.info(success + ' ' * (width-len(success)) + week_sum) Logger.info(f'\n------------- MONTH : {header} --------------') Logger.info(trades + ' ' * (width-len(trades)) + str(len(month_per))) Logger.info(gains + ' ' * (width-len(gains)) + month_percent) Logger.info(aver + ' ' * (width-len(aver)) + str(month_delta)) Logger.info(success + ' ' * (width-len(success)) + month_sum) Logger.info(f'\n------------ ALL TIME : {header} ------------') Logger.info(trades + ' ' * (width-len(trades)) + str(len(all_time_per))) Logger.info(gains + ' ' * (width-len(gains)) + all_time_percent) Logger.info(aver + ' ' * (width-len(aver)) + str(all_time_delta)) Logger.info(success + ' ' * (width-len(success)) + all_time_sum) sys.exit()
def renderCandlestickAstralPattern(self, period=30, saveOnly=False): # get dataframe from technical analysis object df = self.technical_analysis.getDataFrame() if not isinstance(period, int): raise TypeError('Period parameter is not perioderic.') if period < 1 or period > len(df): raise ValueError('Period is out of range') # extract market and granularity from trading dataframe market = df.iloc[0].market granularity = df.iloc[0].granularity df_subset = df.iloc[-period::] fig, axes = plt.subplots(ncols=1, figsize=(12, 6)) #pylint: disable=unused-variable fig.autofmt_xdate() ax1 = plt.subplot(111) ax1.set_title('Astral Candlestick Pattern') plt.plot(df_subset['close'], label='price', color='black') plt.plot(df_subset['ema12'], label='ema12', color='orange') plt.plot(df_subset['ema26'], label='ema26', color='purple') plt.tick_params(axis='x', which='both', bottom=False, top=False, labelbottom=False) df_candlestick = self.df[self.df['astral_buy'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'g^', markersize=8) df_candlestick = self.df[self.df['astral_sell'] is True] df_candlestick_in_range = df_candlestick[ df_candlestick.index >= np.min(df_subset.index)] for idx in df_candlestick_in_range.index.tolist(): plt.plot(idx, df_candlestick_in_range.loc[idx]['close'], 'rv', markersize=8) plt.xlabel(market + ' - ' + str(granularity)) plt.ylabel('Price') plt.xticks(rotation=90) plt.tight_layout() plt.legend() try: Logger.info('creating: graphs/CAP_' + market + '_' + str(granularity) + '.png') plt.savefig('graphs/CAP_' + market + '_' + str(granularity) + '.png', dpi=300) except OSError: raise SystemExit('Unable to save: graphs/CAP_' + market + '_' + str(granularity) + '.png') if saveOnly is False: plt.show()
def getTradeFee(self, market: str) -> float: resp = self.client.get_trade_fee(symbol=market, timestamp=self.getTime()) if 'tradeFee' not in resp: Logger.info('*** getTradeFee(' + market + ') - missing "tradeFee" ***') Logger.info(resp) else: if len(resp['tradeFee']) == 0: Logger.info('*** getTradeFee(' + market + ') - "tradeFee" empty ***') Logger.info(resp) else: if 'taker' not in resp['tradeFee'][0]: Logger.info('*** getTradeFee(' + market + ') - missing "trader" ***') Logger.info(resp) if 'success' in resp: return resp['tradeFee'][0]['taker'] else: return DEFAULT_TRADE_FEE_RATE