跳转至

Research

Apifiny 算法支持交易策略研究的整个生命周期:市场数据记录、数据生成、模型拟合和模拟(也称为回测)。

市场数据

您可以使用自己记录的市场数据或第三方市场数据进行模拟和数据生成。

记录市场数据

一些预先录制的示例数据可以在此处下载。要使用它进行模拟或数据生成,您只需将其解压缩到一个目录中,然后将播放器添加到 json 配置文件中,如下所示(请确保更改路径配置以匹配您的数据目录):

"players" : [
    ["BTCUSDT.HUOBI_Player", ["CobJsonPlayer", {"port": ["BTCUSDT", "HUOBI"], "path": "/data/cob_data"}]], 
    ["ETHUSDT.HUOBI_Player", ["CobJsonPlayer", {"port": ["ETHUSDT", "HUOBI"], "path": "/data/cob_data"}]]
]
我们还提供了两个应用程序供您记录市场数据。接收行情数据的程序和将其写入文件的程序有:

  • ccc_mktpub:接收行情数据并发布到指定的redis
  • ccc_record:从redis中获取对应的数据并保存到本地

用户可以通过配置文件记录不同平台不同产品的实时行情数据。具体配置文件请参考 ${ALGO_HOME}/examples/ccc_mkput 示例。

ccc_mktpub.json:

{
    "instance": {
        "log_path": "/local/cchome/devlogs",
        "levels": 20  
    },
     "servers": {
        "redis_server": "127.0.0.1"
    },
    "symbols": [        
        {"port": ["BTCUSDT", "HUOBI"]},
        {"port": ["ETHUSDT", "HUOBI"]},
        {"port": ["DOGEUSDT", "HUOBI" ]},
        {"port": ["SOLUSDT", "HUOBI"]},
        {"port": ["ADAUSDT", "HUOBI"]}
    ]
}

ccc_record.json:

{
    "data_path ": "/data/cc/prod/cc_record2",
    "instance": {
        "tradeDate":1,
        "is_redis": true,
        "is_optimization":true // true:只保存 BBO 数据。 false: 保存所有数据
    },  
    "servers": {
        "redis_server": "127.0.0.1"
    },
    "symbols": [        
        {"port": ["BTCUSDT", "HUOBI"]},
        {"port": [ "ETHUSDT", "HUOBI"]},
        {"port": ["DOGEUSDT", "HUOBI"]},
        {"port": ["SOLUSDT", "HUOBI"]},
        {"port": ["ADAUSDT ", "HUOBI"]}
    ]
}   

第三方市场数据

Algo 也支持第三方市场数据。

tardis.dev

tardis.dev 提供历史数据订阅,并提供 15 天免费试用。要使用他们的数据进行模拟,您可以使用下面的一些 python 代码下载他们的数据,然后使用类型 TardisPlayer 和相应的数据路径设置您的播放器:

# pip3 install tardis-dev

from lib2to3.pygram import Symbols
from tardis_dev import datasets , get_exchange_details
import logging
import os
import pandas as pd

TARDIS_API = "请从 tardis.dev 获取 API 密钥"


EXCHANGE_MAP = {
    "binance":"BINANCE",
    "binance-futures":"BINANCE_FUTURES",
    "huobi":"HUOBI ",
    "okex-swap":"OKEX_SWAP",
    "okex":"OKEX",
    "okcoin":"OKCOIN",
    "binance-us":"BINANCEUS", "ftx
    ":"FTX"
}

SYMBOL_MAP = {
    "binance":["btcusdt","ethusdt"],    
    "binance-us":['btcusd','ethusd'],
    "binance-futures":["btcusdt","ethusdt"],
    "huobi":[ "btcusdt", "ethusdt"]
    "okex": ["BTC-USDT", "ETH-USDT"],
    "okex-swap":["BTC-USD-SWAP", "ETH-USD-SWAP"],
    "okcoin": ["BTC-USD", "ETH-USD"],
    "ftx": ["BTC-USDT", "ETH-USDT"]
}

def default_file_name(exchange, data_type, date, symbol, format):
    exchange = EXCHANGE_MAP[exchange]
    sym = sym bol.upper()
    if exchange=="FTX":
        if symbol[-5:]=='-PERP':
            sym = sym.replace('-PERP', 'USDSWAP')
            exchange = "FTX_SWAP"
            return f" {exchange}_{sym}_{data_type}.{format}.gz"
    sym = sym.replace('-', '')
    return f"{exchange}_{sym}_{data_type}.{format}。 gz"

def file_name_nested(exchange, data_type, date, symbol, format):
    return f"{exchange}/{data_type}/{date.strftime('%Y-%m-%d')}_{symbol}.{ format}.gz" 

def download_tardis_data(exchange_name, file_types, symbol_list, start_date, end_date, save_path):
    for s_date,e_date in zip(start_date, end_date):
        ss_date = s_date.replace('-', "")
        s_path = f' {save_path}{ss_date}/'
        if not os.path.exists(s_path):
            os.makedirs(s_path)
        try:
            datasets.download(
                exchange = exchange_name,
                data_types =
                file_types, symbols = symbol_list,
                api_key=TARDIS_API,
                from_date = s_date ,
                to_date = e_date,
                download_dir=s_path,
                get_filename=default_file_name
            )
        except Exception as e:
            print(e)

def run(save_path, exchange_list, date_range, file_types):
    date_list = [d.strftime('%Y-%m-%d ') 为了 d in pd.date_range(date_range[0], date_range[1])] 
    start_date = date_list[0:-1]
    end_date = date_list[1:]
    for exchange in exchange_list:
        download_tardis_data(exchange, file_types, SYMBOL_MAP[exchange], start_date , end_date, save_path)

if __name__=="__main__":    
    exchange_list = ["okcoin", "okex", "ftx", "huobi", "binance", "binanceus"]

    #请将这些更改为您喜欢的日期和路径
    date_range = ('20220515', '20220530')
    save_path = "/data/ccc_tardis/"

    file_types = ["trades", "book_snapshot_25"]
    run(save_path, exchange_list, date_range, file_types)

您可以通过将player添加到 json 配置文件中来在模拟中使用 Tardis 数据,如下所示:

"players": [
    ["BCHUSDTSWAP.OKEX_SWAP_Player", ["TardisPlayer", {"port": ["BCHUSDTSWAP", "OKEX_SWAP"], "path": "/data/ccc_tardis"}]], 
    ["BTCUSDTSWAP.OKEX_SWAP_Player", [" TardisPlayer", {"port": ["BTCUSDTSWAP", "OKEX_SWAP"], "path": "/data/ccc_tardis"}]]
]
``


### **安全主数据**
我们存储安全主数据例如 algo_sdk/config/symbol_info/ 目录下的 ticksize,您可以在 C++ 代码中使用 SymbolInfo 类获取一个symbols的所有相关数据。


### **模拟**
要运行模拟(回溯测试),您首先创建一个定义您的策略和数据播放器的 json 配置文件,然后运行 ​​ccc_sim_trader。它将生成订单文件和交易文件。然后,您可以使用 python 脚本或其他工具来分析交易结果。 

下面是一个例子:

配置文件:my_sim_cfg.json
{ "instance": { "license_id":"", "license_key":"",
"log_path": "/data/ccclogs/sim1", "name" :"sim1" }, "sim":{ "ioc_only":true "use_tbbo":true "delay_o2a_us":0, "delay_a2m_us":0 }, "fees":{ "OKEX_SPOT":{ "make":0.0002, "take":0.0006 }, "OKEX_SWAP":{ "make":0.0001, "take":0.0003 } }, "player": [ ["BTCUSDTSWAP.OKEX_SWAP_Player", ["TardisPlayer", {"port": ["BTCUSDTSWAP", "OKEX_SWAP"], "路径": "/data/ccc_tardis"}]], ["ETHUSDTSWAP.OKEX_SWAP_Player ", ["TardisPlayer", {"port": ["ETHUSDTSWAP", "OKEX_SWAP"], "path": "/data/ccc_tardis"}]] ], "risk_formulas": [ ["Port_Risk", ["RiskFormula ", {"components": [[["BTCUSDTSWAP", "OKEX_SWAP"], 1.0], [["ETHUSDTSWAP", "OKEX_SWAP"], 1.0]]}]] ], "accounts": [ [10001, [ "Account",{"risk_formulas":["Port_Risk"],"id":10001}]] ], "symbols":[ {"port":["BTCUSDTSWAP","OKEX_SWAP"],"cid":10001 }, {"port":["ETHUSDTSWAP","OKEX_SWAP"],"cid":10002} ], "samplers":[ ["ts_bt",["TimeSampler",{"halflife":1800,"msecs" : 1000}]] ], "pricing_models": [ ["BTCUSDTSWAP.OKEX_SWAP_midpx", ["MidPx", {"port": ["BTCUSDTSWAP", "OKEX_SWAP"]}]], ["ETHUSDTSWAP.OKEX_SWAP_midpx", [ "MidPx",{"port":["ETHUSDTSWAP","OKEX_SWAP" ]}]] ], "变量": [ ["BTCUSDTSWAP.OKEX_SWAP_br", ["BookReturn", {"port": ["BTCUSDTSWAP", "OKEX_SWAP"], "ref_pm": "BTCUSDTSWAP.OKEX_SWAP_midpx"}]] , ["ETHUSDTSWAP.OKEX_SWAP_br", ["BookReturn", {"port": ["ETHUSDTSWAP", "OKEX_SWAP"], "ref_pm": "ETHUSDTSWAP.OKEX_SWAP_midpx"}]] ], "models": [ ["BTCUSDTSWAP .OKEX_SWAP_m", ["SimpleModel", {"variable": "BTCUSDTSWAP.OKEX_SWAP_br"}]], ["ETHUSDTSWAP.OKEX_SWAP_m", ["SimpleModel", {"variable": "ETHUSDTSWAP.OKEX_SWAP_br"}]] ], "策略":[ ["BTCUSDTSWAP.OKEX_SWAP",["CCTakerStrategy",{"symbol":"BTCUSDTSWAP","trade_market":"OKEX_SWAP","use_margin":true,"account":10001,"use_separate_logs":真,"模型":"BTCUSDTSWAP.OKEX_SWAP_m","dep_pm":"BTCUSDTSWAP.OKEX_SWAP_midpx","use_bps_thold":真,"take_thold":4.0,"low_take_thold":3.0,"max_sweep_bps":2.0,"pos_expanding_cooloff": 1000,"cooloff":1000,"ioc_notional":1000,"max_notional":4000,"max_risk":8000,"start_time":"00:30:00","end_time":"23:59:59"} ]], ["ETHUSDTSWAP.OKEX_SWA P", ["CCTakerStrategy", {"symbol": "ETHUSDTSWAP", "trade_market": "OKEX_SWAP", "use_margin": true, "account": 10001, "use_separate_logs": true, "model": "ETHUSDTSWAP. OKEX_SWAP_m","dep_pm":"ETHUSDTSWAP.OKEX_SWAP_midpx","use_bps_thold":true,"take_thold":4.0,"low_take_thold":3.0,"max_sweep_bps":2.0,"pos_expanding_cooloff":1000,"cooloff":1000," ioc_notional": 1000, "max_notional": 4000, "max_risk": 8000, "start_time": "00:30:00", "end_time": "23:59:59"}]] ] }
运行模拟一天:
ccc_sim_trader YOUR_DIR/my_sim_cfg.json 20220520
模拟过程将订单和交易记录到csv日志文件中。日志路径在 *instance->log_path* 中配置。您可以进入该目录以查看详细信息。

用户可以使用首选的基础设施来运行多天模拟并分析结果。下面是一个简单的模拟过程:

在多核服务器上运行多天模拟:
gen_dates.py -sd 20220515 -ed 20220530 | parallel -j 100 ccc_sim_trader YOUR_DIR/my_sim_cfg.json
模拟完成后,我们来分析一下生成的交易日志:
sim_ana.py -p /data/ccclogs/sim1 -sd 20220515 -ed 20220530
我们会看到这样的交易摘要(结果是从完整的sim结果中截取的,所以请忽略表格中的数据不一致):
dates: 302 +--------------- +-----------+------+----------------+--- -----------+---------------+---------------+------ ---------+------------+ |symbols |边缘 | netUSD_Sharpe | netUSD_mean | netUSD_std | pnlUSD_mean | trdCnt_mean | volUSD_mean |体积平均值 | |---------------+-----------+------+--- ------------+-------------+---------------+------ ---------+---------------+------------| | BTCUSDTSWAP.S | -1.7859 | -0.0107418 | -2.12864 | 198.165 | 1.44714 | 13.6954 | 11919.2 | 27.3311 | | ETHUSDTSWAP.S | 1.62199 | 0.0143254 | 2.18322 | 152.402 | 6.22124 | 18.8477 | 13460.1 | 45.6026 | |全部 | 5.05387 | 0.136787 | 41.6943 | 304.812 | 66.4443 | 134.5 | 82499.8 | 788.076 | +---------------+-----------+-----------------+--- ------------+-------------+---------------+------ ---------+---------------+------------+\
### **数据生成**
您可以使用 Apifiny Algo 的 sim 引擎来生成数据和拟合模型。数据生成功能创建一个包含两种类型数据的数据框:变量值和相关值。变量值给出了某个特征的当前值,从属值给出了远期回报或另一个未来值。因此,在模型拟合算法中,第一个可以用作 X,后一个可以用作 Y。

要生成数据,首先要创建一个配置文件,该文件定义要生成的变量和依赖项。配置还需要包含一个打印机节点来指定如何采样和保存值。

下面是数据生成配置文件的示例:
{ "instance": { "license_id": "", "license_key": "", "log_path": "~/tmp" }, "players": [ ["BTCUSDT.BINANCE_Player", ["TardisPlayer", {"path": "/data/cc/prod/ccc_tardis_2/ccc_tardis", "port": ["BTCUSDT", "BINANCE"]}]] ], "symbols":[ {"cid":20001,"port":["BTCUSDT","BINANCE"]} ], "samplers":[ ["ts_basis",["TimeSampler",{"halflife":1200,"msecs": 500}]], ["ts_basis_2", ["TimeSampler", {"msecs": 100, "halflife": 60}]] ], "pricing_models": [ ["BTCUSDT.BINANCE_midpx", ["MidPx" , {"port": ["BTCUSDT", "BINANCE"]}]], ["BTCUSDT.BINANCE_askpx", ["AskPx", {"port": ["BTCUSDT", "BINANCE"]}]], [ "BTCUSDT.BINANCE_bidpx", ["BidPx", {"port": ["BTCUSDT", "BINANCE"]}]] ], "变量": [ ["BTCUSDT.BINANCE_midpx", ["PriceVar", {"pm ": "BTCUSDT.BINANCE_midpx"}]], ["BTCUSDT.BINANCE_askpx", ["PriceVar", {"pm": "BTCUSDT.BINANCE_askpx"}]], ["BTCUSDT.BINANCE_bidpx", ["PriceVar", { "pm": "BTCUSDT.BINANCE_bidpx"}]], ["BTCUSDT.BINANCE_bboSpread", ["Sub" , {"v1": "BTCUSDT.BINANCE_askpx", "v2": "BTCUSDT.BINANCE_bidpx"}]], ["BTCUSDT.BINANCE_trend", ["趋势", {"pm": "BTCUSDT.BINANCE_midpx", "samplers": "ts_basis_2"}]], ["BTCUSDT.BINANCE_trend_ema", ["VarEma", {"variable": "BTCUSDT.BINANCE_trend", "sampler": "ts_basis"}]] ], "dependants": [ [ "BTCUSDT.BINANCE_dep_0", ["TwapDependant", {"port": ["BTCUSDT", "BINANCE"], "pm": "BTCUSDT.BINANCE_midpx", "tgt_pm": "BTCUSDT.BINANCE_midpx", "base_gap": 0, "dur": 1000}]] ], "printers": [ ["BTCUSDT.BINANCE_printer", ["CsvPrinter", {"path": "YOUR PATH", "dependants": ["BTCUSDT.BINANCE_dep_0"] , "变量": ["BTCUSDT.BINANCE_midpx", "BTCUSDT.BINANCE_askpx", "BTCUSDT.BINANCE_bidpx", "BTCUSDT.BINANCE_bboSpread", "BTCUSDT.BINANCE_trend", "BTCUSDT.BINANCE_trend_ema"], "printing_sampler": "ts_basis_2" }]] ] }

与仿真配置文件相比,数据生成配置文件不需要定义模型和策略components。此外,您需要指定存储数据的路径,以及要打印的依赖项(y)和变量(x),以及打印机节点中的打印samplers。

### 输入模型

如果您已经有模型,可以使用变量 [LinearSum](https://algo.apifiny.com/user_guide/quantlib_configuration/#linearsum) 来保存它。

{ "变量":[ [ "My_Model", [ "LinearSum", { "变量":[ { "权重":0.01343993278740841, "变量":"BTCUSDT.HUOBI_bid_spread", }, { "权重":0.028607602977861364 , "变量": "BTCUSDT.HUOBI_ask_depth", }, { "权重": 0.004402537428023949, "变量": "BTCUSDT.HUOBI_ask_spread", }, { "权重": 0.05897431517277036, "变量": "BTCUSDT.HUOBI_bid_depth", } , ], } ] ] ] }

```

模型拟合/机器学习

Apifiny 算法的设计考虑了数据驱动的交易流程。您可以使用 sklearn 或其他工具来拟合模型,并通过 json 配置将它们插入到 Algo 应用程序中。以下是一些您可以尝试的拟合算法:

  • 线性模型:OLS、Lasso、Ridge、ElasticNet
  • 非线性模型:简单决策树、GBRT、随机森林