Package: fast-trade
Fast TradeA library built with backtest portability and performance in mind for backtest trading strategies. There is also aDataDownloader, which can be used to download compatible kline data from Binance (.com or .us)MotivationsStrategies are cheap. This is the main motivation behind fast-trade. Since a backtest is just a JSON object, strategies can be created, stored, modified, versioned, and re-run easily. Ideally, a backtest could be generated and tested quickly; fast-trade is just the library to handle that.
Fast Trade is also useful for quickly analyzing chart (ohlcv) data and downloading it.Beta TestingI'm using this library to build a platform (live data, charting, paper trading, etc.) and I'm looking for beta testers. If you like this library, send me an email atfasttrade@jedm.dev.ContributingIf you'd like to add a feature, fix a bug, or something else, please clone the repo and fork it. When you're ready, open a PR into this main repo.To get started with local dev, clone the repo, set up a virtual env, source it, then install the dev requirements.gitclonegit@github.com:<YOURGITUSERNAME>/fast-trade.gitcd./fast-trade
python-mvenv.fast_tradesource.fast_trade/bin/activate
pipinstall-rdev_requirements.txtTo generate testing coverage, runcoveragerun-mpytest
coveragereport-mInstallpipinstallfast-tradeUsageSeesma_strategy.jsonandstrategy.jsonfor an example strategy. The basic idea is you describe the "datapoints" then compare them in the "logics". The "datapoints" describe the technical analysis functions to run, and the "logics" describe the logic to use to determine when to enter and exit trades.Example backtest scriptfromfast_tradeimportrun_backtest,validate_backtestbacktest={"base_balance":1000,# start with a balance of 1000"chart_period":"5Min",# time period selected on the chard"chart_start":"2021-08-30 18:00:00",# when to start the chart"chart_stop":"2021-09-06 16:39:00",# when to stop the chart"comission":0.01,# a comission to pay per transaction"datapoints":[# describes the data to use in the logic{"args":[# args are passed to the transformer function30],"transformer":"sma",# technical analysis function to run"name":"sma_short"# reference point for use in logic},{"args":[90],"transformer":"sma","name":"sma_long"},],"enter":[["close",# field to reference, by default this is any column in the data file. Could also be a float or int">",# operator to compare these to"sma_long"# name of datapoint that was prevously defined],["close",">","sma_short"]],"exit":[["close","<","sma_short"]],"trailing_stop_loss":0.05,# optional trailing stop loss"exit_on_end":False,# at then end of the backtest, if true, the trade will exit}# backtests can also come from urls# backtest = "https://raw.githubusercontent.com/jrmeier/fast-trade/master/sma_strategy.json"# returns a mirror of the object, with errors if anyprint(validate_backtest(backtest))# also accepts urls# datafile_path = "https://raw.githubusercontent.com/jrmeier/fast-trade/master/test/ohlcv_data.csv.txt"datafile_path="./BTCUSDT.csv"# returns the summary object and the dataframeresult=run_backtest(backtest,datafile_path)summary=result["summary"]df=result["df"]trade_log_df=result["trade_df"]print(summary)print(df.head())CLIYou can also use the package from the command line. Each command's specific help feature can be viewed by runningft <command> -h.List the commands and their help.ft -hBasic usageThis will download the last month of data for BTCUSD from binance.us and store in aarchive/directory.ft download BTCUSD --exchange binance.usThis will backtest a file with a strategy. By default, it will only show a summary of the backtest. However, if you want to save the results, add the--saveflag and it will go thesaved_backtests/directory.ft backtest ./strategy.json ./archive/BTCUSD_2022.csvYou can also pass in url instead of files.ft backtest https://raw.githubusercontent.com/jrmeier/fast-trade/master/strategy.json ./archive/BTCUSD_2022.csvft backtest strategy.json https://example.com/BTCUSDT_2022.csvYou can validate a backtest before you run it. This doesn't help with the data, but does help with the logic.ft validate stategy.jsonBackteset ModifiersModifying thechart_periodft backtest ./strategy.json ./archive/BTCUSD_2022.csv --mods chart_period 1HModifying thechart_periodand thetrailing_stop_lossft backtest ./strategy.json ./archive/BTCUSD_2022.csv --mods chart_period 1H trailing_stop_loss .05Saving a test result
This generates creates thesaved_backtestdirectory (if it doesn't exist), then inside of there, is another directory with a timestamp, with a chart, the backtest file, the summary, and the raw dataframe as a csv.ft backtest ./strategy.json ./archive/BTCUSD_2022.csv --saveDataDownloaderDownload 1 minute kline/ohlcv from Binance and store them in CSVs in thearchivepath. You can rerun this command to keep the files updated.
It may take awhile to download all of the data the first time, so be patient. It only need to download all of it once, then it will be updated from the most recent date.
Check out the fileupdate_symbol_data.pyif you want to see how it works.Basic example
Download the last 30 days of BTCUSDT from binance.compython -m fast_trade download BTCUSDTft download SYMBOL --archive ARCHIVE_PATH --start START_DATE --end END_DATE --exchange=EXCHANGEDefaults are:EXCHANGE="binance.com"# can be binance.usSTART="2020-01-01"# start dateEND="2020-01-31"# end dateEND='current date'# you'll probably never need thisARCHIVE='./archive'# path the archive folder, which is where the CSVs are storedExamplesdownloads according to the defaultsft downloaddownload data for the symbol LTCBTC using the other defaultsft download LTCBTCdownload data starting January 2021ft download LTCBTC --start=2021-01-01Testingpython-mpytestCoveragecoveragerun-mpytest
coveragereport-mOutputThe output its a dictionary. The summary is a summary all the inputs and of the performace of the model. The df is a Pandas Dataframe, which contains all of the data used in the simulation. And thetrade_dfis a subset of thedfframe which just has all the rows when there was an event. Thebacktestobject is also returned, with the details of how the backtest was run.Example output:{"return_perc":-3.608,"sharpe_ratio":-0.018705921376959495,"buy_and_hold_perc":-13.661,"median_trade_len":1260.0,"mean_trade_len":1430.121951,"max_trade_held":4680.0,"min_trade_len":360.0,"total_num_winning_trades":46,"total_num_losing_trades":119,"avg_win_per":0.134,"avg_loss_per":-0.081,"best_trade_perc":0.592,"min_trade_perc":-2.588,"median_trade_perc":-0.01,"mean_trade_perc":-0.021,"num_trades":165,"win_perc":27.879,"loss_perc":72.121,"equity_peak":10053.901,"equity_final":9651.792,"max_drawdown":9651.792,"total_fees":81.745,"first_tic":"2020-08-30 18:00:00","last_tic":"2020-09-06 16:39:00","total_tics":3334,"test_duration":0.199153}BacktestThe real goal of this project is to get to the point where these strategies can be generated and tested quickly and then be easily iterated on.Below is an example of a very simple strategey. Basically, datapoints are used to build a list of datapoints to look at which must all be true to produce an enter or exit status for that tick.Backtests include all the instructions needed to run the backtest minus the data.Backtest Requirementsname:string, optionaldefault:Nonedescription: a string for quick reference of the backtestchart_period:string, optionaldefault:"1Min"description: a charting period string. allowed values are "Min" (minute), "T" (minute), "D" (day),"H" (hour)Ex."1Min" is 1 minute"2H" is 2 hours"5D" is 5 daysstart: string or timestampoptional,default:""description: The time string of when to start the backtest with%Y-%m-%d %H:%M:%Sdate format or a timestamp. It will be testedEx."2018-05-01 00:00:00"May 1st, 2018 at midnightstop: sting or timestampoptionaldefault:""description: The time string of when to stop the backtest with%Y-%m-%d %H:%M:%Sdate format or a timestampEx."2020-12-28 00:08:00"December 28th, 2020 at 8am."2020-06-01"June 6th, 20201590969600(seconds) June 6th, 20201590969600000(milliseconds) June 6th, 2020base_balance: float or intoptionaldefault: 1000description: The starting balance of trade account. Usually $ or "base" coins for cryptocurrencies.comission: floatoptionaldefault: 0.0description: The "trading fee" per trade. This is subtracted per trade.enter: list,requireddefault:Nonedescription: a list ofLogic's with instructions to compare the data on each tick. EVERY logic item must return True to ENTER the  trade.any_enter: list,optionaldefault:Nonedescription: a list ofLogic's with instructions to compare the data on each tick. ANY LOGIC ITEM can return True to ENTER the trade.exit: listrequireddefault:Nonedescription: a list ofLogic's with instructions to compare the data on each tick. EVERY LOGIC ITEM must return True to EXIT the trade.any_exit: listoptionaldefault:Nonedescription: a list ofLogic's with instructions to compare the data on each tick. ANY LOGIC ITEM can return True to EXIT the trade.datapoints: listoptionaldefault:Nonedescription: This describes how to create the datapoints. Each individual transformer has name that can be referenced in either theenterorexitlogizs. For more information, see (Datapoints)trailing_stop_loss: floatoptionaldefault0description: This sets a trailing stop loss, so the trade will exit immediately, without considering any other action. It is the percentage ot follow for example, to set a stop loss of 5%, set0.05Simple Moving Average Cross exampleThis is an example of a simple moving average cross backtest.{"base_balance":1000,"chart_period":"5T","chart_start":"2020-08-30 18:00:00","chart_stop":"2020-09-06 16:39:00","comission":0.01,"datapoints":[{"args":[30],"transformer":"sma","name":"sma_short"},{"args":[90],"transformer":"sma","name":"sma_long"},],"enter":[["close",">","sma_long"],["close",">","sma_short"]],"exit":[["close","<","sma_short"]],"trailing_stop_loss":0.05,"exit_on_end":False,}LogicDetailEachlogicis contains a singleifstatement. The two variables are the first and last item in the list, with the operator to compare them>,<=.To think of this easily, just say it out loud.
Ex.If the close (closing price) at X time is greater than the "short_sma" (custom datapoint), then return True, else return False.["close",# datapoint or column in provided data">",# operator for comparisson"sma_short"# datapoint or column in provided data]Valid datapoints:openhighlowclosevolumeanydatapoint(seeLogicExample1)any additional columns in your data file or your dataframe (seeLogicExample2)LogicExample1["close",# valid datapoint, always provided">",# logic to use to compare"short"# valid custom datapoint, defined in datapoints]LogicExample2["rsi",# valid custom datapoint, should be defined in datapoints"<",# logic to use to compare70# integer, float, or string]Logic LookbacksLogic lookbacks allow you to confirm a signal by checking the last N periods.["rsi",# valid custom datapoint, should be defined in datapoints">",# logic to use to compare30,# integer, float, or string2# optional, default 0, LogicalLookback number of periods to confirm this signal]DatapointsDatapoints are user defined technical indicators. You can select a definedtransformerfunction to apply the technical analysis. They can reference data and calculate the new values to be referenced inside of any of the logics.Simple SMA example{"name":"sma_short",# transformer name"transformer":"sma",# technical analysis function to be used"args":[20],# arguments to pass to the function, for multiple args, add a "," behind each}Transfomers (Technical Indicators)Available transformer functions are fromFinTACustom datapoints can be added by setting a function name in thedatapoints, then setting that equal to a function that takes in a dataframe as the first argument and whatever arguments passed in.Note:If a transfomer function returns multiple series, fast-trade will name concate the name of the series with the name of the transfomer function.Example:Thebbandsfunction returns two series, one for the upper band and one for the lower band. The name of the series will bebbands_upperandbbands_lower.bbandsreturns 3 columnsupper_bb, middle_band, lower_bb