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