Cryptocurrency#
The backtesting plugin supports various types of cryptocurrency market data, including snapshots, minute-level, and daily.
The cryptocurrency engine supports managing multiple accounts for both spot and futures within a single engine, which differs from the single-account engine usage. The multi-account design follows these principles:
There are different contract types in cryptocurrency markets. The
on_barcallback function will provide data for all contract types within the corresponding time interval, allowing users to design strategies based on market data for different contract types.Backtesting cryptocurrency interface supports
Accountto specify the account to be operated on.
Configurations#
key |
Description |
Notes |
|---|---|---|
“start_data” |
start date |
DATE type, required (e.g., “2020.01.01”) |
“end_data” |
end date |
DATE type, required (e.g., “2020.01.01”) |
“asset_type” |
strategy group |
must be “cryptocurrency” |
“cash” |
initial cash flow (of dictionary type) for each account{“spot”: 100000.“futures”: 100000.“option”: 100000.} |
DOUBLE type, required.
|
“data_type” |
the type of market data |
INT type, required.
|
“msg_as_table” |
process the input market data as table or dictionary |
BOOL type.
|
“matchingMode” |
matching mode |
INT type.
matching with the order price. |
“bench_mark” |
benchmark instrument |
STRING or SYMBOL type, used in |
“latency” |
the latency from order submission to execution |
DOUBLE type, in milliseconds |
“funding_rate” |
funding rate |
TABLE type. For detailed schema, see the table below. |
“enable_indicator_optimize” |
enable indicator calculation optimization |
|
“add_time_column_in_indicator” |
add time column to indicator subscription results |
|
“is_backtest_mode” |
whether is backtesting mode |
|
“data_retention_window” |
data retention policy for indicator optimization |
STRING or INT type. Effective only when both enable_indicator_optimize = true and is_backtest_mode = true:
|
“context” |
strategy context structure |
a dictionary consisting of global strategy variables, for example: |
“orderbook_matching_ratio” |
the proportion of an order that gets filled |
DOUBLE type, default is 1.0, valid range: 0 to 1.0. |
“matching_ratio” |
matching ratio within price intervals |
DOUBLE type, valid range: 0 to 1.0. By default, it is equal to the orderbook_matching_ratio. |
Note: The engine configuration parameters vary for different types of cryptocurrency market data (data_type):
The “orderbook_matching_ratio” and “matching_ratio” keys can only be configured when the type of market data is snapshot, i.e., data_type = 1 or 2.
Schema of configuration “funding_rate”:
Field |
Data Type |
Notes |
|---|---|---|
symbol |
STRING or SYMBOL |
contract |
settlementTime |
TIMESTAMP |
settlement time |
lastfunding_rate |
DECIMAL128(8) |
funding rate at settlement |
Schema of Security Reference#
Field |
Data Type |
Notes |
|---|---|---|
symbol |
SYMBOL or STRING |
symbol |
contractType |
INT |
contract type:
|
optType |
INT |
Options type:
|
strikePrice |
DECIMAL128(8) |
strike price |
contractSize |
DECIMAL128(8) |
contract multiplier |
marginRatio |
DECIMAL128(8) |
margin ratio |
tradeUnit |
DECIMAL128(8) |
trade unit |
priceUnit |
DECIMAL128(8) |
price unit |
priceTick |
DECIMAL128(8) |
price tick |
takerRate |
DECIMAL128(8) |
taker fee rate |
makerRate |
DECIMAL128(8) |
maker fee rate |
deliveryCommissionMode |
INT |
specifies how the transaction fee is calculated when a trade is executed:
|
fundingSettlementMode |
INT |
defines how the funding fee is settled between long and short positions for perpetual futures:
|
lastTradeTime |
TIMESTAMP |
last trade time |
Note:
The margin, fees, and other costs vary for each contract type.
If the contract type is a perpetual future, the position cost calculation must also refer to the configured “funding_rate”.
Snapshot Data#
Schema of Snapshot Data#
When appending data into the backtest engine via the append_data interface:
col_type = {
"symbol": "STRING", "symbolSource": "STRING", "timestamp": "TIMESTAMP", "tradingDay": "DATE",
"lastPrice": "DECIMAL128(8)", "upLimitPrice": "DECIMAL128(8)", "downLimitPrice": "DECIMAL128(8)",
"totalBidQty": "DECIMAL128(8)", "totalOfferQty": "DECIMAL128(8)", "bidPrice": "DECIMAL128(8)[]",
"bidQty": "DECIMAL128(8)[]", "offerPrice": "DECIMAL128(8)[]", "offerQty": "DECIMAL128(8)[]",
"highPrice": "DECIMAL128(8)", "lowPrice": "DECIMAL128(8)", "prevClosePrice": "DECIMAL128(8)",
"settlementPrice": "DECIMAL128(8)", "prevSettlementPrice": "DECIMAL128(8)", "contractType": "INT"
}
message_table = sf.streaming.table(types=col_type, size=0, capacity=10000000)
Schema of snapshot data:
Field |
Data type |
Notes |
|---|---|---|
symbol |
STRING |
symbol |
symbolSource |
STRING |
exchange |
timestamp |
TIMESTAMP |
time stamp |
tradingDay |
DATE |
trading day |
lastPrice |
DECIMAL128(8) |
last price |
upLimitPrice |
DECIMAL128(8) |
upper limit price |
downLimitPrice |
DECIMAL128(8) |
lower limit price |
totalBidQty |
DECIMAL128(8) |
total bid quantity within the interval |
totalOfferQty |
DECIMAL128(8) |
total offer quantity within the interval |
bidPrice |
DECIMAL128(8)[] |
bid price |
bidQty |
DECIMAL128(8)[] |
bid quantity |
offerPrice |
DECIMAL128(8)[] |
offer price |
offerQty |
DECIMAL128(8)[] |
offer quantity |
highPrice |
DECIMAL128(8) |
highest price |
lowPrice |
DECIMAL128(8) |
lowest price |
signal |
DOUBLE[] |
user-defined field |
prevClosePrice |
DECIMAL128(8) |
previous closing price |
settlementPrice |
DECIMAL128(8) |
settlement price |
prevSettlementPrice |
DECIMAL128(8) |
previous settlement price |
contractType |
INT |
contract type:
|
Note: For different data types, please refer to the first chapter for configuration.
After the replay of historical data in backtesting is completed, send a message with symbol=”END”.
message_table = sf.sql("SELECT TOP 1 * FROM messageTable", vars={'messageTable': message_table})
sf.sql("UPDATE messageTable set symbol=END", vars={'messageTable': message_table})
backtester.append_data(message_table)
Snapshot Market Callback Function#
Snapshot market callback function on_snapshot: input the msg parameter.
When msg is a dictionary, it is a snapShot data dictionary with symbol=”key”, where each snapShot object contains the following fields:
Field |
Data Type |
Notes |
|---|---|---|
symbol |
STRING |
symbol |
symbolSource |
STRING |
exchange |
timestamp |
TIMESTAMP |
timestamp |
tradingDay |
DATE |
trading day |
lastPrice |
DECIMAL128(8) |
last traded price |
upLimitPrice |
DECIMAL128(8) |
upper limit price |
downLimitPrice |
DECIMAL128(8) |
lower limit price |
totalBidQty |
DECIMAL128(8) |
total bid quantity within the interval |
totalOfferQty |
DECIMAL128(8) |
total offer quantity within the interval |
bidPrice |
DECIMAL128(8)[] |
bid price |
bidQty |
DECIMAL128(8)[] |
bid quantity |
offerPrice |
DECIMAL128(8)[] |
offer price |
offerQty |
DECIMAL128(8)[] |
offer quantity |
highPrice |
DECIMAL128(8) |
highest price |
lowPrice |
DECIMAL128(8) |
lowest price |
signal |
DOUBLE[] |
user-defined field |
prevClosePrice |
DECIMAL128(8) |
previous closing price |
settlementPrice |
DECIMAL128(8) |
settlement price |
prevSettlementPrice |
DECIMAL128(8) |
previous settlement price |
contractType |
INT |
contract type:
|
Minute-level or Daily Market Data#
Schema of Minute-level Data#
When appending data into the backtest engine via the append_data interface:
col_type = {
"symbol": "SYMBOL", "symbolSource": "SYMBOL", "tradeTime": "TIMESTAMP", "tradingDay": "DATE",
"open": "DECIMAL128(8)", "low": "DECIMAL128(8)", "high": "DECIMAL128(8)", "close": "DECIMAL128(8)",
"volume": "DECIMAL128(8)", "amount": "DECIMAL128(8)", "upLimitPrice": "DECIMAL128(8)",
"downLimitPrice": "DECIMAL128(8)", "prevClosePrice": "DECIMAL128(8)", "settlementPrice": "DECIMAL128(8)",
"prevSettlementPrice": "DECIMAL128(8)", "contractType": "INT"
}
message_table = sf.streaming.table(types=col_type, size=0, capacity=10000000)
Schema of minute-level data:
Field |
Data Type |
Notes |
|---|---|---|
symbol |
SYMBOL |
symbol |
symbolSource |
SYMBOL |
exchange |
tradeTime |
TIMESTAMP |
trade time |
tradingDay |
DATE |
trading day |
open |
DECIMAL128(8) |
open price |
low |
DECIMAL128(8) |
lowest price |
high |
DECIMAL128(8) |
highest price |
close |
DECIMAL128(8) |
close price |
volume |
DECIMAL128(8) |
trading volume |
amount |
DECIMAL128(8) |
trading value (turnover) |
upLimitPrice |
DECIMAL128(8) |
upper limit price |
downLimitPrice |
DECIMAL128(8) |
lower limit price |
signal |
DOUBLE[] |
user-defined field |
prevClosePrice |
DECIMAL128(8) |
previous closing price |
settlementPrice |
DECIMAL128(8) |
settlement price |
prevSettlementPrice |
DECIMAL128(8) |
previous settlement price |
contractType |
INT |
contract type:
|
Note: For different data types, please refer to the first chapter for configuration.
After the replay of historical data in backtesting is completed, send a message with symbol=”END”.
message_table = sf.sql("SELECT TOP 1 * FROM messageTable", vars={'messageTable': message_table})
sf.sql("UPDATE messageTable SET symbol='END'", vars={'messageTable': message_table})
backtester.append_data(message_table)
Market Data Callback Function#
Market data callback function on_bar: input the msg parameter.
When msg is a dictionary, it is a market data dictionary with symbol=”key”, where each market object contains the following fields:
Field |
Data Type |
Notes |
|---|---|---|
symbol |
SYMBOL |
symbol |
symbolSource |
SYMBOL |
exchange |
tradeTime |
TIMESTAMP |
trade time |
tradingDay |
DATE |
trading day |
open |
DECIMAL128(8) |
open price |
low |
DECIMAL128(8) |
lowest price |
high |
DECIMAL128(8) |
highest price |
close |
DECIMAL128(8) |
closing price |
volume |
DECIMAL128(8) |
trading volume |
amount |
DECIMAL128(8) |
trading value (turnover) |
upLimitPrice |
DECIMAL128(8) |
upper limit price |
downLimitPrice |
DECIMAL128(8) |
lower limit price |
signal |
DOUBLE[] |
user-defined field |
prevClosePrice |
DECIMAL128(8) |
previous closing price |
settlementPrice |
DECIMAL128(8) |
settlement price |
prevSettlementPrice |
DECIMAL128(8) |
previous settlement price |
contractType |
INT |
contract type:
|