Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Long-term backtest with parameters changing over each day #171

Open
qihaiqianqiu opened this issue Jan 9, 2025 · 4 comments
Open

Long-term backtest with parameters changing over each day #171

qihaiqianqiu opened this issue Jan 9, 2025 · 4 comments

Comments

@qihaiqianqiu
Copy link

Hi I am currenting trying to make a long-term backtesting by rolling optimized best parameters in last trading day and feed that best parameter set into next trading day.

def backtest_longterm_perday(input_data:List[str], params_set):
    recorder = Recorder(1, 15_000_000_0)
    for idx in range(len(input_data)):
        gc.collect()
        asset = (
        BacktestAsset()
            .data(input_data[idx])
            .constant_latency(100_000, 100_000)
            .linear_asset(1.0)
            .power_prob_queue_model(2.0)
            .no_partial_fill_exchange()
            .trading_value_fee_model(-0.00002, 0.0007)
            .tick_size(0.01)
            .lot_size(0.000001)
            .last_trades_capacity(10000)
            .roi_lb(100)
            .roi_ub(300)
        )

        hbt = ROIVectorMarketDepthBacktest([asset])
        params = params_set[idx]
        adj1 = params['params']['adj1'][0]
        adj2 = params['params']['adj2'][0]
        gamma = params['params']['gamma'][0]
        delta = params['params']['delta'][0]
        max_position = params['params']['max_position'][0]
        momentum_ratio = params['params']['momentum_ratio'][0]
        order_qty = params['params']['order_qty'][0]
        out = gridtrading_glft_momentum_mm(hbt, recorder.recorder, adj1, adj2, gamma, delta, max_position, momentum_ratio, order_qty=order_qty)

        hbt.close()
    stats = LinearAssetRecord(recorder.get(0)).stats(book_size=30_000)
    del recorder
    return stats

I tried to do this with a FOR LOOP, I feed the same recorder object over days to function and finally get its stats. But because I need to feed different parameters for each day, I have to init and close a new hbt and asset object for each day. It turns out that the curve will be init to zero for each day as well - which is not my ideal longterm backtest type, I want it to be a continuous trading.
I found Discontinuities by observing the plot of 09-02 to 09-03, which seems that the return and stocking of 09-02 is erased when it comes to 09-03.
output
Could you please help me to know how to maintain a continous longterm backtesting while keep changing my parameters everyday? Suppose my input data is also a list of well-formated npz files for each day.

Thanks a lot!

@nkaz001
Copy link
Owner

nkaz001 commented Jan 9, 2025

Why not update the parameters within the loop to handle continuous days seamlessly? You can implement the parameter logic directly in the loop. Alternatively, for backtesting efficiency, you could input precomputed updated parameters with associated timestamps, allowing the loop to update parameters at the appropriate times. This approach is a simpler solution. Integrating Custom Data example helps you. But, if you prefer to backtest separately, please refer to the explanation below.

Unfortunately, there is currently no built-in way to maintain the trading state across different hftbacktest instances. Regarding equity, you need to write a custom equity aggregator, such as: equity_day_n+1 += equity_day_n[-1].

But, holding the position across days presents a more complex challenge. If your strategy is high-frequency and has a high turnover rate (frequently altering positions), it might be acceptable to ignore the last position from the previous day and start with a zero position at the beginning of the next day.

If, but, your PnL is significantly affected by positions held across days and the strategy remains high-frequency, closing positions at the end of the day might be necessary for only backtesting purposes to remove the discrepancy. But, this action could unnecessarily impact your strategy, as it introduces an action that would not need in live trading.

Additionally, there is the issue of active orders not being carried over to the next day. This problem is more subtle but can result in losing the queue position during day transitions, which could impact the effectiveness of the strategy.

@qihaiqianqiu
Copy link
Author

Thx a lot, I make it a hbt object that continously running while looping through the parameter dict with timestamp as Key Value. It works out pretty good.

@isslerman
Copy link

Hi guy, interesting question and discussion. Tks all.
We are running here simulations to long-term, days, 10 days... But we have the same parameters and a "parallel" monitor with some results, PNL, and a strategy with parameters inside and a pre-computed data that are fetched by the timestamp of each day.
We are using a polars.df but this consumes a lot of memory, need to be improved or changed to a external access (like Redis).
I saw you configuration here and there is a question that I do not know how to deal.

            .last_trades_capacity(10000)
            .roi_lb(100)
            .roi_ub(300)

The use of the constante value for roi for a long-term simulation is a little trick. For exemplo, the BTC-BRL that is super volatile and in one month has gone from 200k to 600k is a huge range. How I can deal with this range?

  • I can read my data file to check the lb and ub range before start the simulation but this consumes time and proc.
  • I can set a huge range, but this consumes memory for the array (right?)

@nkaz001
Copy link
Owner

nkaz001 commented Jan 14, 2025

Setting a sufficiently large range consumes more memory but is the simplest approach to handling range variations. For example, if the tick size for BTC-BRL is 1 and the range is 50k to 1000k, the memory consumption would be approximately
16MB(950k x 8-byte x 2), which would not pose a problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants