def test_configjson_binance(): config = { "binance": { "api_url": "https://api.binance.com", "api_key": "0000000000000000000000000000000000000000000000000000000000000000", "api_secret": "0000000000000000000000000000000000000000000000000000000000000000", } } try: config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' if os.path.exists('tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json')
def test_configjson_binance_invalid_granularity(): config = { "binance": { "api_url": "https://api.binance.com", "api_key": "0000000000000000000000000000000000000000000000000000000000000000", "api_secret": "0000000000000000000000000000000000000000000000000000000000000000", "config": {} } } try: config['binance']['config']['granularity'] = 60 config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' assert app.getGranularity() == '1h' # default if invalid if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json')
def test_configjson_coinbasepro_invalid_granularity(): config = { "coinbasepro": { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "0000/0000000000/0000000000000000000000000000000000000000000000000000000000/00000000000==", "api_passphrase": "00000000000", "config": {} } } try: config['coinbasepro']['config']['granularity'] = '1m' config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.getGranularity() == 3600 # default if invalid if os.path.exists('tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json')
def __init__(self, app: PyCryptoBot, scanner: bool = False) -> None: self.app = app self.market = app.getMarket() self.exchange = app.getExchange() self.botfolder = "telegram_data" self.botpath = os.path.join(self.app.telegramdatafolder, self.botfolder, self.market) self.filename = self.market + ".json" if not self.app.isSimulation() and self.app.enableTelegramBotControl( ) and not scanner: if not os.path.exists(self.botfolder): os.makedirs(self.botfolder) self.data = {} if not os.path.exists( os.path.join(self.app.telegramdatafolder, "telegram_data")): os.mkdir( os.path.join(self.app.telegramdatafolder, "telegram_data")) if os.path.isfile( os.path.join(self.app.telegramdatafolder, "telegram_data", self.filename)): if not self._read_data(): self.create_bot_data() else: self.create_bot_data() if os.path.isfile( os.path.join(self.app.telegramdatafolder, "telegram_data", "data.json")): write_ok, try_count = False, 0 while not write_ok and try_count <= 5: try_count += 1 self._read_data("data.json") write_ok = True if "markets" not in self.data: self.data.update({"markets": {}}) write_ok = self._write_data("data.json") if "scannerexceptions" not in self.data: self.data.update({"scannerexceptions": {}}) write_ok = self._write_data("data.json") if "opentrades" not in self.data: self.data.update({"opentrades": {}}) write_ok = self._write_data("data.json") else: write_ok, try_count = False, 0 while not write_ok and try_count <= 5: try_count += 1 ds = { "trades": {}, "markets": {}, "scannerexceptions": {}, "opentrades": {} } self.data = ds write_ok = self._write_data("data.json")
def __init__(self, app: PyCryptoBot, scanner: bool = False) -> None: self.app = app self.market = app.getMarket() self.exchange = app.getExchange() self.botfolder = "telegram_data" self.botpath = os.path.join(self.app.telegramdatafolder, self.botfolder, self.market) self.filename = self.market + ".json" if not self.app.isSimulation() and self.app.enableTelegramBotControl( ) and not scanner: if not os.path.exists(self.botfolder): os.makedirs(self.botfolder) self.data = {} if not os.path.exists( os.path.join(self.app.telegramdatafolder, "telegram_data")): os.mkdir( os.path.join(self.app.telegramdatafolder, "telegram_data")) if os.path.isfile( os.path.join(self.app.telegramdatafolder, "telegram_data", self.filename)): self._read_data() else: ds = { "botcontrol": { "status": "active", "manualsell": False, "manualbuy": False, "started": datetime.now().isoformat(), } } self.data = ds self._write_data() if os.path.isfile( os.path.join(self.app.telegramdatafolder, "telegram_data", "data.json")): self._read_data("data.json") if "markets" not in self.data: self.data.update({"markets": {}}) self._write_data() if "scannerexceptions" not in self.data: self.data.update({"scannerexceptions": {}}) self._write_data() else: ds = {"trades": {}, "markets": {}, "scannerexceptions": {}} self.data = ds self._write_data("data.json")
def __init__(self, app:PyCryptoBot, account:TradingAccount) -> None: if app.getExchange() == 'binance': self.api = BAuthAPI(app.getAPIKey(), app.getAPISecret(), app.getAPIURL()) elif app.getExchange() == 'coinbasepro': self.api = CAuthAPI(app.getAPIKey(), app.getAPISecret(), app.getAPIPassphrase(), app.getAPIURL()) else: self.api = None self.app = app self.account = account self.action = 'WAIT' self.buy_count = 0 self.buy_state = '' self.buy_sum = 0 self.eri_text = '' self.fib_high = 0 self.fib_low = 0 self.first_buy_size = 0 self.iterations = 0 self.last_action = 'WAIT' self.last_buy_size = 0 self.last_buy_price = 0 self.last_buy_filled = 0 self.last_buy_fee = 0 self.last_buy_high = 0 self.last_df_index = '' self.sell_count = 0 self.sell_sum = 0
def test_configjson_coinbasepro_invalid_api_passphrase(): config = { "coinbasepro": { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "0000/0000000000/0000000000000000000000000000000000000000000000000000000000/00000000000==", "api_passphrase": "ERROR" } } try: config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) with pytest.raises(TypeError) as execinfo: PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert str(execinfo.value) == 'Coinbase Pro API passphrase is invalid' if os.path.exists('tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json')
def test_configjson_binance_invalid_api_url(): config = { "binance": { "api_url": "ERROR", "api_key": "0000000000000000000000000000000000000000000000000000000000000000", "api_secret": "0000000000000000000000000000000000000000000000000000000000000000", } } try: config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) with pytest.raises(ValueError) as execinfo: PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert str( execinfo.value) == 'Invalid config.json: Binance API URL is invalid' if os.path.exists('tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json')
def test_configjson_islive(): config = { "coinbasepro": { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "0000/0000000000/0000000000000000000000000000000000000000000000000000000000/00000000000==", "api_passphrase": "00000000000", "config": {} } } try: config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert not app.isLive() try: config['coinbasepro']['config']['live'] = 1 config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.isLive() app.setLive(0) assert not app.isLive() if os.path.exists('tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json')
def test_instantiate_model_without_error(): app = PyCryptoBot() assert type(app) is PyCryptoBot app = PyCryptoBot(exchange='coinbasepro') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' app = PyCryptoBot(exchange='binance') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' #app = PyCryptoBot(exchange='dummy') #assert type(app) is PyCryptoBot #assert app.getExchange() == 'dummy' # TODO: validate file exists app = PyCryptoBot(filename='config.json') assert type(app) is PyCryptoBot
def test_configjson_coinbasepro_legacy(): config = { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "0000/0000000000/0000000000000000000000000000000000000000000000000000000000/00000000000==", "api_passphrase": "00000000000" } try: config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro'
def test_configjson_binance(): config = { "binance": { "api_url": "https://api.binance.com", "api_key": "0000000000000000000000000000000000000000000000000000000000000000", "api_secret": "0000000000000000000000000000000000000000000000000000000000000000", } } try: config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance'
def __init__(self, app: PyCryptoBot = None, state: AppState = AppState, df: DataFrame = DataFrame, iterations: int = 0) -> None: if not isinstance(df, DataFrame): raise TypeError("'df' not a Pandas dataframe") if len(df) == 0: raise ValueError("'df' is empty") self._action = 'WAIT' self.app = app self.state = state self._df = df self._df_last = app.getInterval(df, iterations)
def test_configjson_isverbose(): config = { "coinbasepro": { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "0000/0000000000/0000000000000000000000000000000000000000000000000000000000/00000000000==", "api_passphrase": "00000000000", "config": {} } } try: config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.isVerbose() == 0 try: config['coinbasepro']['config']['verbose'] = 1 config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.isVerbose() == 1 if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json')
def test_configjson_coinbasepro_legacy_invalid_api_secret(): config = { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "ERROR", "api_passphrase": "00000000000" } try: config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) with pytest.raises(TypeError) as execinfo: PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert str(execinfo.value) == 'Coinbase Pro API secret is invalid'
def test_configjson_binance_invalid_api_key(): config = { "binance": { "api_url": "https://api.binance.com", "api_key": "ERROR", "api_secret": "0000000000000000000000000000000000000000000000000000000000000000", } } try: config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) with pytest.raises(TypeError) as execinfo: PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert str(execinfo.value) == 'Binance API key is invalid'
def test_instantiate_model_without_error(): if not os.path.exists('config.json'): with pytest.raises(ValueError) as execinfo: PyCryptoBot() assert str( execinfo.value ) == "Invalid config.json: [Errno 2] No such file or directory: 'config.json'" config = { "binance": { "api_url": "https://api.binance.com", "api_key": "0000000000000000000000000000000000000000000000000000000000000000", "api_secret": "0000000000000000000000000000000000000000000000000000000000000000", }, "coinbasepro": { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "0000/0000000000/0000000000000000000000000000000000000000000000000000000000/00000000000==", "api_passphrase": "00000000000" } } try: config_json = json.dumps(config, indent=4) fh = open('config.json', 'w') fh.write(config_json) fh.close() except Exception as err: print(err) app = PyCryptoBot() assert type(app) is PyCryptoBot with open('config.json', 'r') as fh: config = fh.read() config_json = json.loads(config) if 'binance' in config_json: app = PyCryptoBot(exchange='binance') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' if 'coinbasepro' in config_json: app = PyCryptoBot(exchange='coinbasepro') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' if 'dummy' in config_json: app = PyCryptoBot(exchange='dummy') assert type(app) is PyCryptoBot assert app.getExchange() == 'dummy' app = PyCryptoBot(filename='config.json') assert type(app) is PyCryptoBot
from models.PyCryptoBot import PyCryptoBot app = PyCryptoBot(exchange='coinbasepro') print (app.getExchange()) app = PyCryptoBot(exchange='binance') print (app.getExchange()) app = PyCryptoBot(exchange='dummy') print (app.getExchange()) app = PyCryptoBot() print (app.getExchange())
import pandas as pd import numpy as np from datetime import datetime, timedelta import logging, os, random, sched, sys, time from models.PyCryptoBot import PyCryptoBot from models.Trading import TechnicalAnalysis from models.TradingAccount import TradingAccount from models.Telegram import Telegram from views.TradingGraphs import TradingGraphs # production: disable traceback #sys.tracebacklimit = 0 app = PyCryptoBot() s = sched.scheduler(time.time, time.sleep) # initial state is to wait action = 'WAIT' last_action = '' last_df_index = '' buy_state = '' eri_text = '' last_buy = 0 last_buy_high = 0 iterations = 0 buy_count = 0 sell_count = 0 buy_sum = 0 sell_sum = 0
import pandas as pd import numpy as np from datetime import datetime, timedelta import logging, os, random, sched, sys, time from models.PyCryptoBot import PyCryptoBot from models.Trading import TechnicalAnalysis from models.TradingAccount import TradingAccount from models.Telegram import Telegram from views.TradingGraphs import TradingGraphs # production: disable traceback #sys.tracebacklimit = 0 app = PyCryptoBot() s = sched.scheduler(time.time, time.sleep) # initial state is to wait action = 'WAIT' last_action = '' last_df_index = '' buy_state = '' eri_text = '' last_buy = 0 iterations = 0 buy_count = 0 sell_count = 0 buy_sum = 0 sell_sum = 0 fib_high = 0
def test_configjson_binance_granularity(): config = { "binance": { "api_url": "https://api.binance.com", "api_key": "0000000000000000000000000000000000000000000000000000000000000000", "api_secret": "0000000000000000000000000000000000000000000000000000000000000000", "config": {} } } try: granularity = '1m' config['binance']['config']['granularity'] = granularity config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' assert app.getGranularity() == 60 if os.path.exists( 'tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = '5m' config['binance']['config']['granularity'] = granularity config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' assert app.getGranularity() == 300 if os.path.exists( 'tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = '15m' config['binance']['config']['granularity'] = granularity config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' assert app.getGranularity() == 900 if os.path.exists( 'tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = '1h' config['binance']['config']['granularity'] = granularity config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' assert app.getGranularity() == 3600 if os.path.exists( 'tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = '6h' config['binance']['config']['granularity'] = granularity config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' assert app.getGranularity() == 21600 if os.path.exists( 'tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = '1d' config['binance']['config']['granularity'] = granularity config_json = json.dumps(config, indent=4) fh = open('tests/unit_tests/data/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot( filename='tests/unit_tests/data/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'binance' assert app.getGranularity() == 86400 if os.path.exists( 'tests/unit_tests/data/pycryptobot_pytest_config.json'): os.remove('tests/unit_tests/data/pycryptobot_pytest_config.json') except Exception as err: print(err)
def executeJob(sc, app=PyCryptoBot(), trading_data=pd.DataFrame()): """Trading bot job which runs at a scheduled interval""" global action, buy_count, buy_sum, iterations, last_action, last_buy, eri_text, last_df_index, sell_count, sell_sum, buy_state, fib_high, fib_low # increment iterations iterations = iterations + 1 if app.isSimulation() == 0: # 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 trading_dataCopy = trading_data.copy() ta = TechnicalAnalysis(trading_dataCopy) ta.addAll() df = ta.getDataFrame() if app.isSimulation() == 1: # with a simulation df_last will iterate through data df_last = df.iloc[iterations-1:iterations] else: # df_last contains the most recent entry df_last = df.tail(1) if len(df_last.index.format()) > 0: current_df_index = str(df_last.index.format()[0]) else: current_df_index = last_df_index if app.getSmartSwitch() == 1 and app.getExchange() == 'binance' and app.getGranularity() == '1h' and app.is1hEMA1226Bull() == True and app.is6hEMA1226Bull() == True: print ("*** smart switch from granularity '1h' (1 hour) to '15m' (15 min) ***") # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + " smart switch from granularity '1h' (1 hour) to '15m' (15 min)") app.setGranularity('15m') list(map(s.cancel, s.queue)) s.enter(5, 1, executeJob, (sc, app)) elif app.getSmartSwitch() == 1 and app.getExchange() == 'coinbasepro' and app.getGranularity() == 3600 and app.is1hEMA1226Bull() == True and app.is6hEMA1226Bull() == True: print ('*** smart switch from granularity 3600 (1 hour) to 900 (15 min) ***') # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(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)) if app.getSmartSwitch() == 1 and app.getExchange() == 'binance' and app.getGranularity() == '15m' and app.is1hEMA1226Bull() == False and app.is6hEMA1226Bull() == False: print ("*** smart switch from granularity '15m' (15 min) to '1h' (1 hour) ***") # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + " smart switch from granularity '15m' (15 min) to '1h' (1 hour)") app.setGranularity('1h') list(map(s.cancel, s.queue)) s.enter(5, 1, executeJob, (sc, app)) elif app.getSmartSwitch() == 1 and app.getExchange() == 'coinbasepro' and app.getGranularity() == 900 and app.is1hEMA1226Bull() == False and app.is6hEMA1226Bull() == False: print ("*** smart switch from granularity 900 (15 min) to 3600 (1 hour) ***") # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(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)) if app.getExchange() == 'binance' and str(app.getGranularity()) == '1d': if len(df) < 250: # data frame should have 250 rows, if not retry print('error: data frame length is < 250 (' + str(len(df)) + ')') logging.error('error: data frame length is < 250 (' + str(len(df)) + ')') list(map(s.cancel, s.queue)) s.enter(300, 1, executeJob, (sc, app)) else: if len(df) < 300: # data frame should have 300 rows, if not retry print('error: data frame length is < 300 (' + str(len(df)) + ')') logging.error('error: data frame length is < 300 (' + str(len(df)) + ')') list(map(s.cancel, s.queue)) s.enter(300, 1, executeJob, (sc, app)) if len(df_last) > 0: if app.isSimulation() == 0: price = app.getTicker(app.getMarket()) 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]) #deathcross = bool(df_last['deathcross'].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]) # 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]) # criteria for a buy signal if ema12gtema26co == True and macdgtsignal == True and goldencross == True and obv_pc > -5 and elder_ray_buy == True and last_action != 'BUY': action = 'BUY' # criteria for a sell signal elif ema12ltema26co == True and macdltsignal == True and last_action not in ['','SELL']: action = 'SELL' # anything other than a buy or sell, just wait else: action = 'WAIT' last_buy_minus_fees = 0 if last_buy > 0 and last_action == 'BUY': change_pcnt = ((price / last_buy) - 1) * 100 # calculate last buy minus fees fee = last_buy * 0.005 last_buy_minus_fees = last_buy + fee margin = ((price - last_buy_minus_fees) / price) * 100 # loss failsafe sell at fibonacci band if app.allowSellAtLoss() and app.sellLowerPcnt() == None and fib_low > 0 and fib_low >= float(price): action = 'SELL' last_action = 'BUY' log_text = '! Loss Failsafe Triggered (Fibonacci Band: ' + str(fib_low) + ')' print (log_text, "\n") logging.warning(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) # loss failsafe sell at sell_lower_pcnt if app.allowSellAtLoss() and app.sellLowerPcnt() != None and change_pcnt < app.sellLowerPcnt(): action = 'SELL' last_action = 'BUY' log_text = '! Loss Failsafe Triggered (< ' + str(app.sellLowerPcnt()) + '%)' print (log_text, "\n") logging.warning(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if app.getSmartSwitch() == 1 and app.getExchange() == 'binance' and app.getGranularity() == '15m' and change_pcnt >= 2: # profit bank at 2% in smart switched mode action = 'SELL' last_action = 'BUY' log_text = '! Profit Bank Triggered (Smart Switch 2%)' print (log_text, "\n") logging.warning(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if app.getSmartSwitch() == 1 and app.getExchange() == 'coinbasepro' and app.getGranularity() == 900 and change_pcnt >= 2: # profit bank at 2% in smart switched mode action = 'SELL' last_action = 'BUY' log_text = '! Profit Bank Triggered (Smart Switch 2%)' print (log_text, "\n") logging.warning(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) # profit bank at sell_upper_pcnt if app.sellUpperPcnt() != None and change_pcnt > app.sellUpperPcnt(): action = 'SELL' last_action = 'BUY' log_text = '! Profit Bank Triggered (> ' + str(app.sellUpperPcnt()) + '%)' print (log_text, "\n") logging.warning(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) # profit bank at sell at fibonacci band if margin > 3 and app.sellUpperPcnt() != None and fib_high > fib_low and fib_high <= float(price): action = 'SELL' last_action = 'BUY' log_text = '! Profit Bank Triggered (Fibonacci Band: ' + str(fib_high) + ')' print (log_text, "\n") logging.warning(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) # profit bank when strong reversal detected if margin > 3 and obv_pc < 0 and macdltsignal == True: action = 'SELL' last_action = 'BUY' log_text = '! Profit Bank Triggered (Strong Reversal Detected)' print (log_text, "\n") logging.warning(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) # configuration specifies to not sell at a loss if not app.allowSellAtLoss() and margin <= 0: action = 'WAIT' last_action = 'BUY' log_text = '! Ignore Sell Signal (No Sell At Loss)' print (log_text, "\n") logging.warning(log_text) bullbeartext = '' if df_last['sma50'].values[0] == df_last['sma200'].values[0]: bullbeartext = '' elif goldencross == True: bullbeartext = ' (BULL)' elif goldencross == False: bullbeartext = ' (BEAR)' # polling is every 5 minutes (even for hourly intervals), but only process once per interval if (last_df_index != current_df_index): precision = 2 if (price < 0.01): precision = 8 price_text = 'Close: ' + str(app.truncate(price, precision)) ema_text = app.compare(df_last['ema12'].values[0], df_last['ema26'].values[0], 'EMA12/26', precision) macd_text = app.compare(df_last['macd'].values[0], df_last['signal'].values[0], 'MACD', precision) obv_text = 'OBV: ' + str(app.truncate(df_last['obv'].values[0], 4)) + ' (' + str(app.truncate(df_last['obv_pc'].values[0], 2)) + '%)' if elder_ray_buy == True: eri_text = 'ERI: buy' elif elder_ray_sell == True: eri_text = 'ERI: sell' else: eri_text = 'ERI:' if hammer == True: log_text = '* Candlestick Detected: Hammer ("Weak - Reversal - Bullish Signal - Up")' print (log_text, "\n") logging.debug(log_text) if shooting_star == True: log_text = '* Candlestick Detected: Shooting Star ("Weak - Reversal - Bearish Pattern - Down")' print (log_text, "\n") logging.debug(log_text) if hanging_man == True: log_text = '* Candlestick Detected: Hanging Man ("Weak - Continuation - Bearish Pattern - Down")' print (log_text, "\n") logging.debug(log_text) if inverted_hammer == True: log_text = '* Candlestick Detected: Inverted Hammer ("Weak - Continuation - Bullish Pattern - Up")' print (log_text, "\n") logging.debug(log_text) if three_white_soldiers == True: log_text = '*** Candlestick Detected: Three White Soldiers ("Strong - Reversal - Bullish Pattern - Up")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if three_black_crows == True: log_text = '* Candlestick Detected: Three Black Crows ("Strong - Reversal - Bearish Pattern - Down")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if morning_star == True: log_text = '*** Candlestick Detected: Morning Star ("Strong - Reversal - Bullish Pattern - Up")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if evening_star == True: log_text = '*** Candlestick Detected: Evening Star ("Strong - Reversal - Bearish Pattern - Down")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if three_line_strike == True: log_text = '** Candlestick Detected: Three Line Strike ("Reliable - Reversal - Bullish Pattern - Up")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if abandoned_baby == True: log_text = '** Candlestick Detected: Abandoned Baby ("Reliable - Reversal - Bullish Pattern - Up")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if morning_doji_star == True: log_text = '** Candlestick Detected: Morning Doji Star ("Reliable - Reversal - Bullish Pattern - Up")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if evening_doji_star == True: log_text = '** Candlestick Detected: Evening Doji Star ("Reliable - Reversal - Bearish Pattern - Down")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) if two_black_gapping == True: log_text = '*** Candlestick Detected: Two Black Gapping ("Reliable - Reversal - Bearish Pattern - Down")' print (log_text, "\n") logging.debug(log_text) # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') ' + log_text) ema_co_prefix = '' ema_co_suffix = '' if ema12gtema26co == True: ema_co_prefix = '*^ ' ema_co_suffix = ' ^*' elif ema12ltema26co == True: ema_co_prefix = '*v ' ema_co_suffix = ' v*' elif ema12gtema26 == True: ema_co_prefix = '^ ' ema_co_suffix = ' ^' elif ema12ltema26 == True: ema_co_prefix = 'v ' ema_co_suffix = ' v' macd_co_prefix = '' macd_co_suffix = '' if macdgtsignalco == True: macd_co_prefix = '*^ ' macd_co_suffix = ' ^*' elif macdltsignalco == True: macd_co_prefix = '*v ' macd_co_suffix = ' v*' elif macdgtsignal == True: macd_co_prefix = '^ ' macd_co_suffix = ' ^' elif macdltsignal == True: macd_co_prefix = 'v ' macd_co_suffix = ' v' obv_prefix = '' obv_suffix = '' if float(obv_pc) > 0: obv_prefix = '^ ' obv_suffix = ' ^' elif float(obv_pc) < 0: obv_prefix = 'v ' obv_suffix = ' v' if app.isVerbose() == 0: if last_action != '': output_text = current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + str(app.getGranularity()) + ' | ' + price_text + ' | ' + ema_co_prefix + ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + ' | ' + obv_prefix + obv_text + obv_suffix + ' | ' + eri_text + ' | ' + action + ' | Last Action: ' + last_action else: output_text = current_df_index + ' | ' + app.getMarket() + bullbeartext + ' | ' + str(app.getGranularity()) + ' | ' + price_text + ' | ' + ema_co_prefix + ema_text + ema_co_suffix + ' | ' + macd_co_prefix + macd_text + macd_co_suffix + ' | ' + obv_prefix + obv_text + obv_suffix + ' | ' + eri_text + ' | ' + action + ' ' if last_action == 'BUY': if last_buy_minus_fees > 0: margin = str(app.truncate((((price - last_buy_minus_fees) / price) * 100), 2)) + '%' else: margin = '0%' output_text += ' | ' + margin logging.debug(output_text) print (output_text) else: logging.debug('-- Iteration: ' + str(iterations) + ' --' + bullbeartext) if last_action == 'BUY': margin = str(app.truncate((((price - last_buy) / price) * 100), 2)) + '%' logging.debug('-- Margin: ' + margin + '% --') logging.debug('price: ' + str(app.truncate(price, precision))) logging.debug('ema12: ' + str(app.truncate(float(df_last['ema12'].values[0]), precision))) logging.debug('ema26: ' + str(app.truncate(float(df_last['ema26'].values[0]), precision))) logging.debug('ema12gtema26co: ' + str(ema12gtema26co)) logging.debug('ema12gtema26: ' + str(ema12gtema26)) logging.debug('ema12ltema26co: ' + str(ema12ltema26co)) logging.debug('ema12ltema26: ' + str(ema12ltema26)) logging.debug('sma50: ' + str(app.truncate(float(df_last['sma50'].values[0]), precision))) logging.debug('sma200: ' + str(app.truncate(float(df_last['sma200'].values[0]), precision))) logging.debug('macd: ' + str(app.truncate(float(df_last['macd'].values[0]), precision))) logging.debug('signal: ' + str(app.truncate(float(df_last['signal'].values[0]), precision))) logging.debug('macdgtsignal: ' + str(macdgtsignal)) logging.debug('macdltsignal: ' + str(macdltsignal)) logging.debug('obv: ' + str(obv)) logging.debug('obv_pc: ' + str(obv_pc)) logging.debug('action: ' + action) # informational output on the most recent entry print('') print('================================================================================') txt = ' Iteration : ' + str(iterations) + bullbeartext print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Timestamp : ' + str(df_last.index.format()[0]) print('|', txt, (' ' * (75 - len(txt))), '|') print('--------------------------------------------------------------------------------') txt = ' Close : ' + str(app.truncate(price, precision)) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' EMA12 : ' + str(app.truncate(float(df_last['ema12'].values[0]), precision)) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' EMA26 : ' + str(app.truncate(float(df_last['ema26'].values[0]), precision)) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Crossing Above : ' + str(ema12gtema26co) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Currently Above : ' + str(ema12gtema26) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Crossing Below : ' + str(ema12ltema26co) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Currently Below : ' + str(ema12ltema26) print('|', txt, (' ' * (75 - len(txt))), '|') if (ema12gtema26 == True and ema12gtema26co == True): txt = ' Condition : EMA12 is currently crossing above EMA26' elif (ema12gtema26 == True and ema12gtema26co == False): txt = ' Condition : EMA12 is currently above EMA26 and has crossed over' elif (ema12ltema26 == True and ema12ltema26co == True): txt = ' Condition : EMA12 is currently crossing below EMA26' elif (ema12ltema26 == True and ema12ltema26co == False): txt = ' Condition : EMA12 is currently below EMA26 and has crossed over' else: txt = ' Condition : -' print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' SMA20 : ' + str(app.truncate(float(df_last['sma20'].values[0]), precision)) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' SMA200 : ' + str(app.truncate(float(df_last['sma200'].values[0]), precision)) print('|', txt, (' ' * (75 - len(txt))), '|') print('--------------------------------------------------------------------------------') txt = ' MACD : ' + str(app.truncate(float(df_last['macd'].values[0]), precision)) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Signal : ' + str(app.truncate(float(df_last['signal'].values[0]), precision)) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Currently Above : ' + str(macdgtsignal) print('|', txt, (' ' * (75 - len(txt))), '|') txt = ' Currently Below : ' + str(macdltsignal) print('|', txt, (' ' * (75 - len(txt))), '|') if (macdgtsignal == True and macdgtsignalco == True): txt = ' Condition : MACD is currently crossing above Signal' elif (macdgtsignal == True and macdgtsignalco == False): txt = ' Condition : MACD is currently above Signal and has crossed over' elif (macdltsignal == True and macdltsignalco == True): txt = ' Condition : MACD is currently crossing below Signal' elif (macdltsignal == True and macdltsignalco == False): txt = ' Condition : MACD is currently below Signal and has crossed over' else: txt = ' Condition : -' print('|', txt, (' ' * (75 - len(txt))), '|') print('--------------------------------------------------------------------------------') txt = ' Action : ' + action print('|', txt, (' ' * (75 - len(txt))), '|') print('================================================================================') if last_action == 'BUY': txt = ' Margin : ' + margin + '%' print('|', txt, (' ' * (75 - len(txt))), '|') print('================================================================================') # if a buy signal if action == 'BUY': last_buy = price buy_count = buy_count + 1 fee = float(price) * 0.005 price_incl_fees = float(price) + fee buy_sum = buy_sum + price_incl_fees # if live if app.isLive() == 1: # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') BUY at ' + price_text) if app.isVerbose() == 0: logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | ' + price_text + ' | BUY') print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '|', price_text, '| BUY', "\n") else: print('--------------------------------------------------------------------------------') print('| *** Executing LIVE Buy Order *** |') print('--------------------------------------------------------------------------------') # display balances print (app.getBaseCurrency(), 'balance before order:', account.getBalance(app.getBaseCurrency())) print (app.getQuoteCurrency(), 'balance before order:', account.getBalance(app.getQuoteCurrency())) # execute a live market buy resp = app.marketBuy(app.getMarket(), float(account.getBalance(app.getQuoteCurrency()))) logging.info(resp) # display balances print (app.getBaseCurrency(), 'balance after order:', account.getBalance(app.getBaseCurrency())) print (app.getQuoteCurrency(), 'balance after order:', account.getBalance(app.getQuoteCurrency())) # if not live else: if app.isVerbose() == 0: logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | ' + price_text + ' | BUY') print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '|', price_text, '| BUY') bands = ta.getFibonacciRetracementLevels(float(price)) print (' Fibonacci Retracement Levels:', str(bands)) ta.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': fib_low = 0 fib_high = bands[first_key] if first_key == 'ratio1_618': fib_low = bands[first_key] fib_high = bands[first_key] * 2 else: fib_low = bands[first_key] elif len(bands) == 2: first_key = list(bands.keys())[0] second_key = list(bands.keys())[1] fib_low = bands[first_key] fib_high = bands[second_key] else: print('--------------------------------------------------------------------------------') print('| *** Executing TEST Buy Order *** |') print('--------------------------------------------------------------------------------') if app.shouldSaveGraphs() == 1: tradinggraphs = TradingGraphs(ta) ts = datetime.now().timestamp() filename = app.getMarket() + '_' + str(app.getGranularity()) + '_buy_' + str(ts) + '.png' tradinggraphs.renderEMAandMACD(len(trading_data), 'graphs/' + filename, True) # if a sell signal elif action == 'SELL': sell_count = sell_count + 1 fee = float(price) * 0.005 price_incl_fees = float(price) - fee sell_sum = sell_sum + price_incl_fees # if live if app.isLive() == 1: # telegram if app.isTelegramEnabled(): telegram = Telegram(app.getTelegramToken(), app.getTelegramClientId()) telegram.send(app.getMarket() + ' (' + str(app.getGranularity()) + ') SELL at ' + price_text) if app.isVerbose() == 0: logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | ' + price_text + ' | SELL') print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '|', price_text, '| SELL') bands = ta.getFibonacciRetracementLevels(float(price)) print (' Fibonacci Retracement Levels:', str(bands), "\n") if len(bands) >= 1 and len(bands) <= 2: if len(bands) == 1: first_key = list(bands.keys())[0] if first_key == 'ratio1': fib_low = 0 fib_high = bands[first_key] if first_key == 'ratio1_618': fib_low = bands[first_key] fib_high = bands[first_key] * 2 else: fib_low = bands[first_key] elif len(bands) == 2: first_key = list(bands.keys())[0] second_key = list(bands.keys())[1] fib_low = bands[first_key] fib_high = bands[second_key] else: print('--------------------------------------------------------------------------------') print('| *** Executing LIVE Sell Order *** |') print('--------------------------------------------------------------------------------') # display balances print (app.getBaseCurrency(), 'balance before order:', account.getBalance(app.getBaseCurrency())) print (app.getQuoteCurrency(), 'balance before order:', account.getBalance(app.getQuoteCurrency())) # execute a live market sell resp = app.marketSell(app.getMarket(), float(account.getBalance(app.getBaseCurrency()))) logging.info(resp) # display balances print (app.getBaseCurrency(), 'balance after order:', account.getBalance(app.getBaseCurrency())) print (app.getQuoteCurrency(), 'balance after order:', account.getBalance(app.getQuoteCurrency())) # if not live else: if app.isVerbose() == 0: sell_price = float(str(app.truncate(price, precision))) last_buy_price = float(str(app.truncate(float(last_buy), precision))) buy_sell_diff = round(np.subtract(sell_price, last_buy_price), precision) if (sell_price != 0): buy_sell_margin_no_fees = str(app.truncate((((sell_price - last_buy_price) / sell_price) * 100), 2)) + '%' else: buy_sell_margin_no_fees = '0%' # calculate last buy minus fees buy_fee = last_buy_price * 0.005 last_buy_price_minus_fees = last_buy_price + buy_fee if (sell_price != 0): buy_sell_margin_fees = str(app.truncate((((sell_price - last_buy_price_minus_fees) / sell_price) * 100), 2)) + '%' else: buy_sell_margin_fees = '0%' logging.info(current_df_index + ' | ' + app.getMarket() + ' ' + str(app.getGranularity()) + ' | SELL | ' + str(sell_price) + ' | BUY | ' + str(last_buy_price) + ' | DIFF | ' + str(buy_sell_diff) + ' | MARGIN NO FEES | ' + str(buy_sell_margin_no_fees) + ' | MARGIN FEES | ' + str(buy_sell_margin_fees)) print ("\n", current_df_index, '|', app.getMarket(), str(app.getGranularity()), '| SELL |', str(sell_price), '| BUY |', str(last_buy_price), '| DIFF |', str(buy_sell_diff) , '| MARGIN NO FEES |', str(buy_sell_margin_no_fees), '| MARGIN FEES |', str(buy_sell_margin_fees), "\n") else: print('--------------------------------------------------------------------------------') print('| *** Executing TEST Sell Order *** |') print('--------------------------------------------------------------------------------') if app.shouldSaveGraphs() == 1: tradinggraphs = TradingGraphs(ta) ts = datetime.now().timestamp() filename = app.getMarket() + '_' + str(app.getGranularity()) + '_sell_' + str(ts) + '.png' tradinggraphs.renderEMAandMACD(len(trading_data), 'graphs/' + filename, True) # last significant action if action in [ 'BUY', 'SELL' ]: last_action = action last_df_index = str(df_last.index.format()[0]) if iterations == len(df): print ("\nSimulation Summary\n") if buy_count > sell_count: fee = price * 0.005 last_price_minus_fees = price - fee sell_sum = sell_sum + last_price_minus_fees sell_count = sell_count + 1 print (' Buy Count :', buy_count) print (' Sell Count :', sell_count, "\n") if sell_count > 0: print (' Margin :', str(app.truncate((((sell_sum - buy_sum) / sell_sum) * 100), 2)) + '%', "\n") print (' ** non-live simulation, assuming highest fees', "\n") else: print (str(app.getTime()), '|', app.getMarket() + bullbeartext, '|', str(app.getGranularity()), '| Current Price:', price) # decrement ignored iteration iterations = iterations - 1 # if live if app.isLive() == 1: # update order tracker csv if app.getExchange() == 'binance': account.saveTrackerCSV(app.getMarket()) elif app.getExchange() == 'coinbasepro': account.saveTrackerCSV() if app.isSimulation() == 1: if iterations < 300: if app.simuluationSpeed() in [ 'fast', 'fast-sample' ]: # fast processing executeJob(sc, app, trading_data) else: # slow processing list(map(s.cancel, s.queue)) s.enter(1, 1, executeJob, (sc, app, trading_data)) else: # poll every 5 minute list(map(s.cancel, s.queue)) s.enter(300, 1, executeJob, (sc, app))
def test_configjson_coinbasepro_granularity(): config = { "coinbasepro": { "api_url": "https://api.pro.coinbase.com", "api_key": "00000000000000000000000000000000", "api_secret": "0000/0000000000/0000000000000000000000000000000000000000000000000000000000/00000000000==", "api_passphrase": "00000000000", "config": {} } } try: granularity = 60 config['coinbasepro']['config']['granularity'] = granularity config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.getGranularity() == granularity if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = 300 config['coinbasepro']['config']['granularity'] = granularity config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.getGranularity() == granularity if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = 900 config['coinbasepro']['config']['granularity'] = granularity config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.getGranularity() == granularity if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = 3600 config['coinbasepro']['config']['granularity'] = granularity config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.getGranularity() == granularity if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = 21600 config['coinbasepro']['config']['granularity'] = granularity config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.getGranularity() == granularity if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json') except Exception as err: print(err) try: granularity = 86400 config['coinbasepro']['config']['granularity'] = granularity config_json = json.dumps(config) fh = open('/tmp/pycryptobot_pytest_config.json', 'w') fh.write(config_json) fh.close() app = PyCryptoBot(filename='/tmp/pycryptobot_pytest_config.json') assert type(app) is PyCryptoBot assert app.getExchange() == 'coinbasepro' assert app.getGranularity() == granularity if os.path.exists('/tmp/pycryptobot_pytest_config.json'): os.remove('/tmp/pycryptobot_pytest_config.json') except Exception as err: print(err)
from models.exchange.binance import PublicAPI as BPublicAPI from models.exchange.coinbase_pro import PublicAPI as CPublicAPI from models.exchange.kucoin import PublicAPI as KPublicAPI 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):
from models.PyCryptoBot import PyCryptoBot from models.Trading import TechnicalAnalysis from views.TradingGraphs import TradingGraphs app = PyCryptoBot() trading_data = app.getHistoricalData(app.getMarket(), app.getGranularity()) ta = TechnicalAnalysis(trading_data) ta.addAll() df_data = ta.getDataFrame() df_fib = ta.getFibonacciRetracementLevels() df_sr = ta.getSupportResistanceLevels() print(df_data) print(df_fib) print(df_sr) graphs = TradingGraphs(ta) #graphs.renderBuySellSignalEMA1226MACD(saveOnly=False) #graphs = TradingGraphs(ta) #graphs.renderPercentageChangeHistogram() #graphs.renderCumulativeReturn() #graphs.renderPercentageChangeScatterMatrix() graphs.renderFibonacciBollingerBands(period=24)
from models.PyCryptoBot import PyCryptoBot from models.Trading import TechnicalAnalysis from models.Binance import AuthAPI as BAuthAPI, PublicAPI as BPublicAPI from models.CoinbasePro import AuthAPI as CBAuthAPI, PublicAPI as CBPublicAPI from views.TradingGraphs import TradingGraphs #app = PyCryptoBot() app = PyCryptoBot('binance') tradingData = app.getHistoricalData(app.getMarket(), app.getGranularity()) technicalAnalysis = TechnicalAnalysis(tradingData) technicalAnalysis.addAll() tradinggraphs = TradingGraphs(technicalAnalysis) tradinggraphs.renderFibonacciRetracement(True) tradinggraphs.renderSupportResistance(True) tradinggraphs.renderCandlesticks(30, True) tradinggraphs.renderSeasonalARIMAModelPrediction(1, True)
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))
from models.PyCryptoBot import PyCryptoBot from models.Trading import TechnicalAnalysis app = PyCryptoBot() df = app.getHistoricalData(app.getMarket(), app.getGranularity()) model = TechnicalAnalysis(df) model.addATR(14) df = model.getDataFrame() print(df)
import pandas as pd from datetime import datetime, timedelta from models.PyCryptoBot import PyCryptoBot, truncate as _truncate from models.AppState import AppState from models.Trading import TechnicalAnalysis from models.TradingAccount import TradingAccount from models.Stats import Stats from models.helper.MarginHelper import calculate_margin from views.TradingGraphs import TradingGraphs from models.Strategy import Strategy from models.helper.LogHelper import Logger # minimal traceback sys.tracebacklimit = 1 app = PyCryptoBot() account = TradingAccount(app) Stats(app, account).show() technical_analysis = None state = AppState(app, account) state.initLastAction() s = sched.scheduler(time.time, time.sleep) def executeJob(sc=None, app: PyCryptoBot = None, state: AppState = None, trading_data=pd.DataFrame()): """Trading bot job which runs at a scheduled interval"""
def load_configs(): exchanges_loaded = [] try: with open("screener.json", encoding='utf8') as json_file: config = json.load(json_file) except IOError as err: raise (err) try: with open("config.json", encoding='utf8') as json_file: bot_config = json.load(json_file) except IOError as err: print(err) try: for exchange in config: ex = CryptoExchange(exchange) exchange_config = config[ex.value] if ex == CryptoExchange.BINANCE: binance_app = PyCryptoBot(exchange=ex) binance_app.public_api = BPublicAPI( bot_config[ex.value]["api_url"]) binance_app.scanner_quote_currencies = exchange_config.get( 'quote_currency', ['USDT']) binance_app.granularity = Granularity( Granularity.convert_to_enum( exchange_config.get('granularity', '1h'))) binance_app.adx_threshold = exchange_config.get( 'adx_threshold', 25) binance_app.volatility_threshold = exchange_config.get( 'volatility_threshold', 9) binance_app.minimum_volatility = exchange_config.get( 'minimum_volatility', 5) binance_app.minimum_volume = exchange_config.get( 'minimum_volume', 20000) binance_app.volume_threshold = exchange_config.get( 'volume_threshold', 20000) binance_app.minimum_quote_price = exchange_config.get( 'minimum_quote_price', 0.0000001) binance_app.selection_score = exchange_config.get( 'selection_score', 10) binance_app.tv_screener_ratings = [ rating.upper() for rating in exchange_config.get( 'tv_screener_ratings', ['STRONG_BUY']) ] exchanges_loaded.append(binance_app) elif ex == CryptoExchange.COINBASEPRO: coinbase_app = PyCryptoBot(exchange=ex) coinbase_app.public_api = CPublicAPI() coinbase_app.scanner_quote_currencies = exchange_config.get( 'quote_currency', ['USDT']) coinbase_app.granularity = Granularity( Granularity.convert_to_enum( int(exchange_config.get('granularity', '3600')))) coinbase_app.adx_threshold = exchange_config.get( 'adx_threshold', 25) coinbase_app.volatility_threshold = exchange_config.get( 'volatility_threshold', 9) coinbase_app.minimum_volatility = exchange_config.get( 'minimum_volatility', 5) coinbase_app.minimum_volume = exchange_config.get( 'minimum_volume', 20000) coinbase_app.volume_threshold = exchange_config.get( 'volume_threshold', 20000) coinbase_app.minimum_quote_price = exchange_config.get( 'minimum_quote_price', 0.0000001) coinbase_app.selection_score = exchange_config.get( 'selection_score', 10) coinbase_app.tv_screener_ratings = [ rating.upper() for rating in exchange_config.get( 'tv_screener_ratings', ['STRONG_BUY']) ] exchanges_loaded.append(coinbase_app) elif ex == CryptoExchange.KUCOIN: kucoin_app = PyCryptoBot(exchange=ex) kucoin_app.public_api = KPublicAPI( bot_config[ex.value]["api_url"]) kucoin_app.scanner_quote_currencies = exchange_config.get( 'quote_currency', ['USDT']) kucoin_app.granularity = Granularity( Granularity.convert_to_enum( exchange_config.get('granularity', '1h'))) kucoin_app.adx_threshold = exchange_config.get( 'adx_threshold', 25) kucoin_app.volatility_threshold = exchange_config.get( 'volatility_threshold', 9) kucoin_app.minimum_volatility = exchange_config.get( 'minimum_volatility', 5) kucoin_app.minimum_volume = exchange_config.get( 'minimum_volume', 20000) kucoin_app.volume_threshold = exchange_config.get( 'volume_threshold', 20000) kucoin_app.minimum_quote_price = exchange_config.get( 'minimum_quote_price', 0.0000001) kucoin_app.selection_score = exchange_config.get( 'selection_score', 10) kucoin_app.tv_screener_ratings = [ rating.upper() for rating in exchange_config.get( 'tv_screener_ratings', ['STRONG_BUY']) ] exchanges_loaded.append(kucoin_app) else: raise ValueError(f"Invalid exchange found in config: {ex}") except AttributeError as e: print(f"Invalid exchange: {e}...ignoring.") return exchanges_loaded