def test_validate_backtest_base_balance(): mock_backtest = {"base_balance": 1000} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["base_balance"] is None mock_backtest = {"base_balance": "1000"} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["base_balance"] is None mock_backtest = {"base_balance": "1000.0"} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["base_balance"] is None mock_backtest = {"base_balance": 1000.0} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["base_balance"] is None
def test_validate_backtest_empty_1(): mock_backtest = {} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["datapoints"]["error"] is True assert backtest_mirror["exit"]["error"] is True assert backtest_mirror["enter"]["error"] is True
def test_validate_basic_invalid(): mock_backtest = { "base_balance": "c1000", "chart_period": "1Min22", } backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["base_balance"].get("error") is True assert backtest_mirror["chart_period"].get("error") is True
def run_backtest(backtest: dict, ohlcv_path: str = "", df: pd.DataFrame = None, summary=True): """ Parameters backtest: dict, required, object containing the logic to test and other details ohlcv_path: string or list, required, where to find the csv file of the ohlcv data df: pandas dataframe indexed by date Returns dict summary dict, summary of the performace of backtest df dataframe, object used in the backtest trade_log, dataframe of all the rows where transactions happened """ try: perf_start_time = datetime.datetime.utcnow() new_backtest = prepare_new_backtest(backtest) if ohlcv_path: df = build_data_frame(backtest, ohlcv_path) df = apply_backtest_to_df(df, new_backtest) if summary: summary, trade_log = build_summary(df, perf_start_time, new_backtest) else: perf_stop_time = datetime.datetime.utcnow() summary = { "test_duration": (perf_stop_time - perf_start_time).total_seconds() } trade_log = None return { "summary": summary, "df": df, "trade_df": trade_log, "backtest": new_backtest, } except Exception as e: return { "summary": None, "df": None, "trade_df": None, "backtest": None, "error": e, "backtest_validation": validate_backtest(backtest), }
def test_validate_data_points_invalid_name(): mock_datapoints = [ { "args": [30], "transformer": "ema", "name": "" }, ] mock_backtest = {"datapoints": mock_datapoints} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["datapoints"].get("error") is True
def test_validate_data_points_invalid(): mock_datapoints = [ { "args": [30], "transformer": "fake_news_transformer", "name": "sma_short" }, ] mock_backtest = {"datapoints": mock_datapoints} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["datapoints"].get("error") is True
def test_validate_data_points_valid(): mock_datapoints = [ { "args": [30], "transformer": "sma", "name": "sma_short" }, ] mock_backtest = {"datapoints": mock_datapoints} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["datapoints"] is None
def test_validate_enter_logic_valid(): mock_datapoints = [ { "args": [30], "transformer": "sma", "name": "sma_short" }, ] mock_enter_logic = [["close", ">", "sma_short"]] mock_backtest = {"datapoints": mock_datapoints, "enter": mock_enter_logic} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["datapoints"] is None
def test_validate_enter_logic_invalid_1(): mock_datapoints = [ { "args": [30], "transformer": "sma", "name": "sma_short" }, ] mock_enter_logic = [["close", ">", "sma_shortee"]] mock_backtest = {"datapoints": mock_datapoints, "enter": mock_enter_logic} backtest_mirror = validate_backtest(mock_backtest) assert backtest_mirror["enter"].get("error") is True
def test_validate_any_exit_logic_invalid_1(): mock_datapoints = [ { "args": [30], "transformer": "sma", "name": "wtf" }, ] mock_exit_logic = [["close", ">", "no name here"]] mock_backtest = { "datapoints": mock_datapoints, "exit": [], "enter": [], "any_exit": mock_exit_logic } backtest_mirror = validate_backtest(mock_backtest) print(backtest_mirror) assert backtest_mirror["any_exit"].get("error") is True
def main(): parser = argparse.ArgumentParser( description="Fast Trade CLI", prog="ft", ) sub_parsers = parser.add_subparsers() # build the argement parser downloading stuff default_archive_path = os.path.join(os.getcwd(), "archive") default_end_date = datetime.datetime.utcnow() default_start_date = default_end_date - datetime.timedelta(days=30) download_parser = sub_parsers.add_parser("download", help="download data") download_parser.add_argument("symbol", help="symbol to download", type=str) download_parser.add_argument( "--archive", help="path to directory to serve as the 'archive'", type=str, default=default_archive_path, ) download_parser.add_argument( "--start", help= "first date to start downloading data from. Recently Listed coins might not have a lot of data.", type=str, default=default_start_date.strftime("%Y-%m-%d"), ) download_parser.add_argument( "--end", help="Last date to download data. Defaults to today.", type=str, default=default_end_date.strftime("%Y-%m-%d"), ) download_parser.add_argument( "--exchange", help="Which exchange to download data from. Defaults to binance.com", type=str, default="binance.com", choices=["binance.com", "binance.us"], ) backtest_parser = sub_parsers.add_parser("backtest", help="backtest a strategy") backtest_parser.add_argument( "strategy", help="path to strategy file", type=str, ) backtest_parser.add_argument("data", help="path to data file for kline data.") backtest_parser.add_argument("--mods", help="Modifiers for strategy/backtest", nargs="*") backtest_parser.add_argument( "--save", help="save the backtest results to a directory", action="store_true", default=False, ) backtest_parser.add_argument( "--plot", help="plot the backtest results", action="store_true", default=False, ) validate_backtest_parser = sub_parsers.add_parser( "validate", help="validate a strategy file") validate_backtest_parser.add_argument( "strategy", help="path to strategy file", type=str, ) validate_backtest_parser.add_argument( "--mods", help="Modifiers for strategy/backtest", nargs="*") args = parser.parse_args() command = sys.argv[1] if command == "download": update_symbol_data(args.symbol, args.start, args.end, args.archive, args.exchange) if command == "backtest": # match the mods to the kwargs strat_obj = open_strat_file(args.strategy) if not strat_obj: print("Could not open strategy file: {}".format(args.strategy)) sys.exit(1) if args.mods: mods = {} i = 0 while i < len(args.mods): mods[args.mods[i]] = args.mods[i + 1] i += 2 strat_obj = {**strat_obj, **mods} backtest = run_backtest(strat_obj, data_path=args.data) if args.save: save(backtest, backtest["backtest"]) if args.plot: create_plot(backtest["df"]) plt.show() print(backtest) pprint(backtest["summary"]) if command == "validate": strat_obj = open_strat_file(args.strategy) if args.mods: mods = {} i = 0 while i < len(args.mods): mods[args.mods[i]] = args.mods[i + 1] i += 2 strat_obj = {**strat_obj, **mods} backtest = validate_backtest(strat_obj) pprint(backtest)
"args": [30], "transformer": "sma", "name": "sma_shorst" }, { "args": [90], "transformer": "sma", "name": "sma_long" }, ], "enter": [["close", ">", "sma_long_wrong"], ["close", ">", "sma_short"]], "exit": [["close", "<", "sma_short"], ["close", "<", 5]], "trailing_stop_loss": 0.05, "exit_on_end": False, } if __name__ == "__main__": # datafile = "./BTCUSDT.csv" datafile = "./BTCUSDT.csv" tmp_start = datetime.datetime.utcnow() # backtest = generate_backtest() # print("backtest: ",json.dumps(backtest, indent=2) # test = run_backtest(backtest, ohlcv_path=datafile, summary=True) res = validate_backtest(backtest) print(res) # print(backtest["enter"]) # print(test["trade_df"]) . # print(json.dumps(test["summary"], indent=2))
def main(): if len(sys.argv) < 2: print(format_all_help_text()) return command = sys.argv[1] args = parse_args(sys.argv[2:]) if command == "backtest": # check for help if "help" in args.keys(): print(format_command(command)) return strat_obj = open_strat_file(args["backtest"]) strat_obj = {**strat_obj, **args} if args.get("data", "").endswith(".csv"): # use a csv file data = args["data"] res = run_backtest(strat_obj, ohlcv_path=data) else: # load from the archive archive = args.get("archive", "./archive") archive_df = load_archive_to_df(strat_obj["symbol"], archive) archive_df = prepare_df(archive_df, strat_obj) res = run_backtest(strat_obj, df=archive_df) if res["summary"]: print(json.dumps((res["summary"]), indent=2)) else: print("There was an error:") print(json.dumps((res["backtest_validation"]), indent=2)) if args.get("save"): save(res, strat_obj) if args.get("plot"): create_plot(res["df"]) plt.show() return if command == "help": print(format_all_help_text()) return if command == "download": default_end = ( datetime.datetime.utcnow() + datetime.timedelta(days=1) ).strftime("%Y-%m-%d") symbol = args.get("symbol", "BTCUSDT") arc_path = args.get("archive", "./archive/") start_date = args.get("start", "2017-01-01") end_date = args.get("end", default_end) exchange = args.get("exchange", "binance.com") update_symbol_data(symbol, start_date, end_date, arc_path, exchange) print("Done downloading ", symbol) return if command == "validate": print("args: ",args) backtest = open_strat_file(args["backtest"]) if not backtest: print("backtest not found! ") return print("backtest: ",backtest) backtest = {**backtest, **args} res = validate_backtest(backtest) print(json.dumps(res, indent=2)) return print("Command not found") print(format_all_help_text())
0, "datapoints": [{ "args": [14], "name": "er", "transformer": "er" }, { "args": [13], "name": "zlema", "transformer": "zlema" }], "enter": [["zlema", ">", "close", 1]], "exit": [["er", "<", 0, 1]], "exit_on_end": False, "start": "2021-01-01 22:30:00", "stop": "2021-03-11 23:30:59", "trailing_stop_loss": 0 } if __name__ == "__main__": # datafile = "./BTCUSDT.csv" datafile = "./archive/BTCUSDT_2021.csv" # test = run_backtest(backtest, ohlcv_path=datafile, summary=True) # print(test["summary"]) errors = validate_backtest(backtest) print(errors)