nkaz001 / hftbacktest

A high-frequency trading and market-making backtesting and trading bot in Python and Rust, which accounts for limit orders, queue positions, and latencies, utilizing full tick data for trades and order books, with real-world crypto market-making examples for Binance Futures
MIT License
1.96k stars 383 forks source link

How to set Spot asset type and include multiple types within the same asset #150

Open River-Shi opened 3 weeks ago

River-Shi commented 3 weeks ago

Can Asset Type be set to spot? I understand from the documentation that we can integrate spot data by integrating custom data, but I believe setting the asset type with spot_asset(1.0) would be more elegant.

asset = (
    BacktestAsset()
        .data(['usdm/btcusdt_20240809.npz'])
        .initial_snapshot('usdm/btcusdt_20240808_eod.npz')
        # Asset type:
        # * Linear
        # * Inverse.
        # 1.0 represents the contract size, the asset's value per quoted price.
        .linear_asset(1.0)
        .constant_latency(10_000_000, 10_000_000)
        .risk_adverse_queue_model()
        .no_partial_fill_exchange()
        .trading_value_fee_model(0.0002, 0.0007)
        .tick_size(0.1)
        .lot_size(0.001)
        .last_trades_capacity(0)
)
hbt = HashMapMarketDepthBacktest([asset])

Also, is there a way to set different asset types within the same asset? For instance, how can I include spot and linear for btcusdt?

asset = (
        BacktestAsset()
            .data(['data/{}_{}.npz'.format(asset_name, date) for date in range(20230731, 20230732)])
            .initial_snapshot('data/{}_20230730_eod.npz'.format(asset_name))
            .linear_asset(1.0)
            .intp_order_latency(latency_data)
            .power_prob_queue_model(2.0)
            .no_partial_fill_exchange()
            .trading_value_fee_model(-0.00005, 0.0007)
            .tick_size(asset_info['tick_size'])
            .lot_size(asset_info['lot_size'])
            .roi_lb(0.0)
            .roi_ub(mid_price * 5)
            .last_trades_capacity(10000)
    )
nkaz001 commented 3 weeks ago

If you need to execute your order on spot or dynamically compute a value from the market depth, you can input the spot asset as well. The custom data integration example demonstrates how to work with data that is not directly from the trading asset, such as on-chain data or news. Additionally, adding the full asset data can slow down backtesting because it requires replaying tick-by-tick data. If you only need specific values from spot, the example shows a much faster approach.

Also, it may be confusing, but linear_asset and inverse_asset don't necessarily refer to futures. These simply set how the equity and trading value are calculated. Spot is inherently linear, so for a spot asset, you just use linear_asset.

Please see the following example.

spot = (
        # Set a spot asset data
        BacktestAsset()
            .data(['data/{}_{}.npz'.format(asset_name, date) for date in range(20230731, 20230732)])
            .initial_snapshot('data/{}_20230730_eod.npz'.format(asset_name))
            .linear_asset(1.0)
            .intp_order_latency(latency_data)
            .power_prob_queue_model(2.0)
            .no_partial_fill_exchange()
            .trading_value_fee_model(-0.00005, 0.0007)
            .tick_size(asset_info['tick_size'])
            .lot_size(asset_info['lot_size'])
            .roi_lb(0.0)
            .roi_ub(mid_price * 5)
            .last_trades_capacity(10000)
    )

linear_futures = (
        # Set a linear futures asset data
        BacktestAsset()
            .data(['data/{}_{}.npz'.format(asset_name, date) for date in range(20230731, 20230732)])
            .initial_snapshot('data/{}_20230730_eod.npz'.format(asset_name))
            .linear_asset(1.0)
            .intp_order_latency(latency_data)
            .power_prob_queue_model(2.0)
            .no_partial_fill_exchange()
            .trading_value_fee_model(-0.00005, 0.0007)
            .tick_size(asset_info['tick_size'])
            .lot_size(asset_info['lot_size'])
            .roi_lb(0.0)
            .roi_ub(mid_price * 5)
            .last_trades_capacity(10000)
    )

# asset_no of spot is 0
# asset_no of linear_futures is 1
hbt = ROIVectorMarketDepthBacktest([spot, linear_futures])
River-Shi commented 3 weeks ago

If you need to execute your order on spot or dynamically compute a value from the market depth, you can input the spot asset as well. The custom data integration example demonstrates how to work with data that is not directly from the trading asset, such as on-chain data or news. Additionally, adding the full asset data can slow down backtesting because it requires replaying tick-by-tick data. If you only need specific values from spot, the example shows a much faster approach.

Also, it may be confusing, but linear_asset and inverse_asset don't necessarily refer to futures. These simply set how the equity and trading value are calculated. Spot is inherently linear, so for a spot asset, you just use linear_asset.

Please see the following example.

spot = (
        # Set a spot asset data
        BacktestAsset()
            .data(['data/{}_{}.npz'.format(asset_name, date) for date in range(20230731, 20230732)])
            .initial_snapshot('data/{}_20230730_eod.npz'.format(asset_name))
            .linear_asset(1.0)
            .intp_order_latency(latency_data)
            .power_prob_queue_model(2.0)
            .no_partial_fill_exchange()
            .trading_value_fee_model(-0.00005, 0.0007)
            .tick_size(asset_info['tick_size'])
            .lot_size(asset_info['lot_size'])
            .roi_lb(0.0)
            .roi_ub(mid_price * 5)
            .last_trades_capacity(10000)
    )

linear_futures = (
        # Set a linear futures asset data
        BacktestAsset()
            .data(['data/{}_{}.npz'.format(asset_name, date) for date in range(20230731, 20230732)])
            .initial_snapshot('data/{}_20230730_eod.npz'.format(asset_name))
            .linear_asset(1.0)
            .intp_order_latency(latency_data)
            .power_prob_queue_model(2.0)
            .no_partial_fill_exchange()
            .trading_value_fee_model(-0.00005, 0.0007)
            .tick_size(asset_info['tick_size'])
            .lot_size(asset_info['lot_size'])
            .roi_lb(0.0)
            .roi_ub(mid_price * 5)
            .last_trades_capacity(10000)
    )

# asset_no of spot is 0
# asset_no of linear_futures is 1
hbt = ROIVectorMarketDepthBacktest([spot, linear_futures])

Thanks