from algo import Algo from ema_algo import Ema_Algo from api import fetch_chart_data_yahoo, fetch_chart_data_backtest import datetime import json import random import os import pytz """ Function that takes in data and returns a buy, sell, or hold singal per interval """ def backtest_algo(algo : Algo, timestamps, prices, init_offset=5, starting_money=10000): # take a fraction of the OG data (or a set #) assert len(timestamps) == len(prices) assert init_offset < len(timestamps) # make sure enough data to start with current_timestamps = timestamps[:init_offset] current_prices = prices[:init_offset] is_bought = 0.0 # not holding anything current_liquid = 10000 shares_owned = 0 buy_data = [] sell_data = [] for i in range(init_offset, len(timestamps)): # update prices array and run algo current_timestamps.append(timestamps[i]) current_prices.append(prices[i]) current_signal = algo.detemine_signal(current_timestamps, current_prices) cur_p = current_prices[-1] cur_t = current_timestamps[-1] if current_signal == 1.0: # signal is to buy if is_bought == 0.0: # if we haven't bought, purchase shares_owned = current_liquid / cur_p current_liquid = 0 is_bought = 1.0 buy_data.append(i) #print("buy", shares_owned, current_liquid, datetime.datetime.fromtimestamp(timestamps[i])) elif current_signal == 0.0: # signal sell all if is_bought == 1.0: # if we have bought, sell! current_liquid = shares_owned * cur_p shares_owned = 0 is_bought = 0.0 sell_data.append(i) #print('sell', shares_owned, current_liquid, datetime.datetime.fromtimestamp(timestamps[i])) # calculate total assets assets = prices[-1] * shares_owned + current_liquid percent_gain = 100 * (assets - starting_money) / starting_money print(assets, percent_gain) # create a json to store the reuslts results = { "timestamps" : timestamps, "prices" : prices, "buy_indices" : buy_data, "sell_indices" : sell_data, "percent_gain" : percent_gain, "starting_assets" : starting_money, "final_assets" : assets, "algo_name" : algo.name, "algo_graph_data" : algo.graph_data } return results # store all algo name, buy, sell, price data, timestamps, into a json so it can be viewed as a trial # caluclate some metrics (NOW: only how much money gained, how many trades, trades per day... etc) ticker_bank = ['BTC/USD', 'ETH/USD', 'XRP/USD'] year_bank = [2024, 2025] # time_bank = [0] # max_seconds = 24 * 60 * 60 # timedelta(seconds=rand_second) + datetime(created with 0 time) """ Runs N trials with random parameters """ def run_batch(batch_name, algo, num_trials=100): i = 1 while i <= num_trials: # pick a random set of parameters rand_ticker = ticker_bank[random.randint(0, len(ticker_bank) - 1)] rand_year = year_bank[random.randint(0, len(year_bank) - 1)] rand_day = random.randint(1, 31) rand_month = random.randint(1, 12) # ensure the date is valid rand_date = None try: rand_date = datetime.datetime(rand_year, rand_month, rand_day) except ValueError: # date creation failed continue # ensure date is not in future curr_date = datetime.datetime.now() if rand_date > curr_date: continue # pull chart data for these params and run the algo data = fetch_chart_data_backtest(rand_ticker, '1Min', rand_date) results = backtest_algo(algo, data['timestamps'], data['prices'], 13) # TODO: make this generalized url_params = { "ticker" : rand_ticker, "period" : '5D', "interval" : '1Min', } # store the results in into a file trial_data = { "chart_data" : data, "url_params" : url_params, "backtest_results" : results } # make a new directory for the batch path = f'batches/{batch_name}' if i == 1: print(path) try: os.makedirs(path) except PermissionError: print(f"Permission denied: Unable to create {path}.") return except Exception as e: print(f"An error occurred: {e}") return percent_gain = results['percent_gain'] date_format = datetime.datetime.timestamp(rand_date) file_name = f'{path}/{str(percent_gain).replace('-', 'neg').replace('.', 'd')}_{rand_ticker.replace('/', '')}_{date_format}.json' fd = open(file_name, 'w') fd.write(json.dumps(trial_data)) fd.close() # increment trial num i += 1 # run_batch('test', Ema_Algo(), 5) def test(): print("MAIN simulate.py") ema_algo = Ema_Algo() ticker = 'XRP/USD' period = '5d' interval = '1m' # get data # data = fetch_chart_data(ticker, period, interval) # period_end_date = datetime.datetime.now(tz=datetime.timezone.utc) - datetime.timedelta(days=7) # print(period_end_date) data = fetch_chart_data_backtest('XRP/USD', '1D', None, datetime.timedelta(weeks=52)) print(data.keys()) url_params = { "ticker" : ticker, "period" : period, "interval" : interval, } results = backtest_algo(ema_algo, data['timestamps'], data['prices'], 13) # write the data into a json to be viewed in a chart trial_data = { "chart_data" : data, "url_params" : url_params, "backtest_results" : results } fd = open('bt-recent.json', 'w') fd.write(json.dumps(trial_data)) fd.close() test() # run_batch('test-1-ema', Ema_Algo(), 10)