跳转至

Tutorial: ccc_simple_taker

在本教程中,我们将创建一个更完整的交易应用程序。 它监听市场数据,每分钟发出一个 IOC 指令。

我们在示例中开始使用 Apfiny Algo 策略框架。 该框架采用插件机制,交易逻辑将作为组件实现并注册到系统中。 之后,您使用 json 配置文件来创建策略和其他组件的实例。

此示例将所有交易逻辑放入单个组件 SimpleTakeStrategy。 它继承自基类 Strategy 和 OrderSender。

Create trading strategy

#include "base/Strategy.h"
#include "components/TimerManager.h"
#include "components/TradeApiManager.h"
#include "components/SymbolManager.h"
#include "base/Order.h"
#include "base/SymbolInfo.h"

class SimpleTakeStrategy: public Strategy, public OrderSender {
public:
    using Strategy::Strategy;

    //implements Strategy
    void init() override;
    void onNotify() override;
    SymbolInfo *getSymbolInfo() override { return _si; }
    void onCommand(json& cmd) override {}
    bool isUseMargin() override { return _useMargin; }
    string& marginSource() override { return _marginSource; }

    //imlements SymbolListener
    void onQuote(long cid, const SymbolInfo& si) override;
    void onTick(long cid, const SymbolInfo& si) override;
    void onQuoteStale(long cid, const SymbolInfo& si) override {}

    //implements TimerListener
    void onTimer(TimerHandler* th, long msecs) override;

    //implements OrderSender
    void onOrderCreated(LOrder* order) override {};
    void onOrderAcked(LOrder* order) override {};
    void onOrderRejected(LOrder* order) override {};
    void onOrderCancelCreated(LOrder* order) override {};
    void onOrderCancelAcked(LOrder* order) override {};
    void onOrderCancelRejected(LOrder* order) override {};
    void onOrderExec(TradeDirs side, double px, double qty, Liquidity liq, LOrder* order) override {};
    void onOrderCanceled(LOrder* order) override {};
    void onOrderClosed(LOrder* order) override {};

protected:
    TimerManager *_timerMgr;
    SymbolInfo* _si;
    bool _useMargin = false;
    string _marginSource = "spot";
    bool _hasTimeEvt = false;

    double _order_size;
    double _take_from_mid;
};
#include "SimpleTakeStrategy.h"

void SimpleTakeStrategy::init() {
    auto symMgr = SymbolManager::instance();

    string symbol = _cfg.at("symbol");
    string exch = _cfg.at("trade_market");
    auto sh = symMgr->getSymbolHandler(symbol, exch);
    sh->addListener(this);
    _si = &sh->symbolInfo();

    _timerMgr = TimerManager::instance();
    TimerHandler* th = _timerMgr->getTimerHandler(60000);
    th->addListener(this);

    _take_from_mid = _cfg.at("take_from_mid_bps").get<double>() * 0.0001;
    _order_size = _cfg.at("order_size");
}

void SimpleTakeStrategy::onNotify() {
    if(!_si->is_ready()) 
        return;

    if(_hasTimeEvt) {
        _hasTimeEvt = false;

        std::cout << "send a random IOC order" << std::endl;

        LOrder* ord = new LOrder();
        ord->sender = this;
        ord->account = 101;
        ord->use_margin = false;
        ord->margin_source = "spot";
        ord->side = BUY;
        ord->si = _si;
        ord->px = _si->mid_px() * (1 + _take_from_mid);
        ord->qty = _order_size;
        ord->remainingQty = ord->qty;
        ord->signal = 0.0;
        ord->spread = _si->spread();
        ord->tif = Tif::TIF_IOC;
        ord->intention = OrderIntention::OI_AGGRESSIVE;

        TradeApi* tradeApi = TradeApiManager::instance()->tradeApi();
        tradeApi->sendOrder(ord);
    }
}

void SimpleTakeStrategy::onQuote(long cid, const SymbolInfo& si) {

}

void SimpleTakeStrategy::onTick(long cid, const SymbolInfo& si) {

}

void SimpleTakeStrategy::onTimer(TimerHandler* th, long msecs) {
    _hasTimeEvt = true;
}

Register your strategy class

class MyComponentFactory : public XlibComponentFactory
{
public:
    Strategy *getStrategy(const string &type, const string &name, const json &attr)
    {
        if (type == "SimpleTakeStrategy") 
            return new SimpleTakeStrategy(name, attr);            
        return nullptr;
    }   
};

Complete the application

int main(int argc, char **argv)
{
    if (argc <= 1)
    {
        std::cout << "Usage: ccc_simple_taker cfg_path" << std::endl;
        return 0;
    }

    //load configuration
    std::time_t t = std::time(0);
    std::tm *now = std::localtime(&t);
    int date = (now->tm_year + 1900) * 10000 + (now->tm_mon + 1) * 100 + now->tm_mday;
    json cfg = loadConfig(argv[1],date);
    json &instCfg = cfg["instance"];
    instCfg["tradeDate"] = date;
    instCfg["isLive"] = true;

    //setup logger
    string instName = getJsonValue(instCfg, "name", string("instname"));
    string logPath = getJsonValue(instCfg, "log_path", string("."));
    date = instCfg["tradeDate"];
    logPath += "/" + to_string(date);
    mkdirs(logPath);
    logPath += "/inst_" + instName + ".log";
    int logLevel = getJsonValue(instCfg, "log_level", qts::log4z::LOG_LEVEL_DEBUG);
    QTS_LOG_START(logLevel, logPath);

    //setup your custom component factory to load components
    XlibComponentFactoryPtr xmgr(new MyComponentFactory);
    StrategyManager::instance()->addXlibComponentFactory(xmgr);

    //start cctrader
    std::cout << "Starting trader ..." << std::endl;
    CCTradeEngine client(cfg);
    client.initialize();
    client.run();
}

Configure

我们使用 json 文件来配置交易应用程序该文件包含有关 api 密钥、日志路径和策略组件的信息。 请更新以下示例配置中的 API 密钥信息:

{
    "instance": {
        "log_path": "./simple_taker_test_01",        
        "name": "simple_taker_test_01"
    },      
    "servers":{
        "redis_server":"127.0.0.1"                           
    }, 
    "exchanges":[
        {"exchange":"OKEX_SWAP","trade_type":"Direct","market_data_type":"Direct"}
    ],
    "apikeys": {
     "OKEX_SWAP": {
        "key": "enter your api key",
        "secret": "enter your api secert",
        "pass": "enter your api passphrase"
         }      
    },
    "fees": {
        "OKEX_SWAP": {
            "make": 0.0,
            "take": 0.0002
        }
    },    
    "symbol_info": {
    }, 
    "symbols": [
        {"cid": 1001, "port": ["BTCUSDTSWAP", "OKEX_SWAP"]}        
    ],
    "samplers": [
    ],
    "pricing_models": [
    ],
    "variables": [      
    ],
    "models": [
    ],
    "strategies": [                                 
        ["BTCUSDTSWAP.OKEX_SWAP", [
            "SimpleTakerStrategy", {
                "symbol": "BTCUSDTSWAP",
                "trade_market": "OKEX_SWAP",
                "take_from_mid_bps": -10.0,
                "order_size": 0.0001
            }]]                          
    ]
}

Build

该版本包含完整的源代码和用于构建它的 premake 文件。 请按照以下步骤构建:

cd algo_sdk/examples/ccc_simple_taker/build_scripts
premake4 gmake
make -j 10 config=release

Run

Apfiny Algo 依赖于多个共享库,因此您需要先设置一些环境变量。

使用 algo_sdk 的路径设置环境变量 ALGO_HOME。 例如 /data/cc/algo_sdk:

export ALGO_HOME=YOUR_ALGO_SDK_PATH

Setup other environment variables:

export TZ=UTC
export LD_LIBRARY_PATH=${ALGO_HOME}/bin:$LD_LIBRARY_PATH
export PATH=${ALGO_HOME}/bin:$PATH

You can start the application now. It takes one command line argument, which is the path to a json configuration file.

ccc_simple_taker ${ALGO_HOME}/examples/ccc_simple_taker/cfg/simple_taker_cfg.json