WtHftStraDemo.h
source: wtcpp/folder98/folder06/folder2/file02.md
#pragma once
#include <unordered_set>
#include <memory>
#include <thread>
#include <mutex>
#include "../Includes/HftStrategyDefs.h"
class WtHftStraDemo : public HftStrategy
{
public:
WtHftStraDemo(const char* id);
~WtHftStraDemo();
private:
void check_orders();
public:
virtual const char* getName() override;
virtual const char* getFactName() override;
virtual bool init(WTSVariant* cfg) override;
virtual void on_init(IHftStraCtx* ctx) override;
virtual void on_tick(IHftStraCtx* ctx, const char* code, WTSTickData* newTick) override;
virtual void on_bar(IHftStraCtx* ctx, const char* code, const char* period, uint32_t times, WTSBarStruct* newBar) override;
virtual void on_trade(IHftStraCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double qty, double price, const char* userTag) override;
virtual void on_position(IHftStraCtx* ctx, const char* stdCode, bool isLong, double prevol, double preavail, double newvol, double newavail) override;
virtual void on_order(IHftStraCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double totalQty, double leftQty, double price, bool isCanceled, const char* userTag) override;
virtual void on_channel_ready(IHftStraCtx* ctx) override;
virtual void on_channel_lost(IHftStraCtx* ctx) override;
virtual void on_entrust(uint32_t localid, bool bSuccess, const char* message, const char* userTag) override;
private:
// 交易参数
std::string _code; // 交易合约
uint32_t _secs; // 订单超时秒数
uint32_t _freq; // 交易频率控制(指定时间内限制信号数)
int32_t _offset; // 指令价格偏移
int32_t _count;
// 内部数据
IHftStraCtx* _ctx;
uint32_t _unit;
double _reserved;
bool _stock;
WTSTickData* _last_tick; // 上一笔行情
typedef std::unordered_set<uint32_t> IDSet;
IDSet _orders; // 策略相关订单
std::mutex _mtx_ords;
uint64_t _last_entry_time; // 上次入场时间
bool _channel_ready; // 通道是否就绪
uint32_t _last_calc_time;
uint32_t _cancel_cnt; // 正在撤销的订单数
};
WtHftStraDemo.cpp
#include "WtHftStraDemo.h"
#include "../Includes/IHftStraCtx.h"
#include "../Includes/WTSVariant.hpp"
#include "../Includes/WTSDataDef.hpp"
#include "../Includes/WTSContractInfo.hpp"
#include "../Share/TimeUtils.hpp"
#include "../Share/decimal.h"
#include "../Share/fmtlib.h"
extern const char* FACT_NAME;
WtHftStraDemo::WtHftStraDemo(const char* id)
: HftStrategy(id)
, _last_tick(NULL)
, _last_entry_time(UINT64_MAX)
, _channel_ready(false)
, _last_calc_time(0)
, _stock(false)
, _unit(1)
, _cancel_cnt(0)
, _reserved(0)
{
}
WtHftStraDemo::~WtHftStraDemo()
{
if (_last_tick)
_last_tick->release();
}
const char* WtHftStraDemo::getName()
{
return "HftDemoStrategy";
}
const char* WtHftStraDemo::getFactName()
{
return FACT_NAME;
}
bool WtHftStraDemo::init(WTSVariant* cfg)
{
//这里演示一下外部传入参数的获取
_code = cfg->getCString("code");
_secs = cfg->getUInt32("second");
_freq = cfg->getUInt32("freq");
_offset = cfg->getUInt32("offset");
_reserved = cfg->getDouble("reserve");
_stock = cfg->getBoolean("stock");
_unit = _stock ? 100 : 1;
_count = cfg->getUInt32("count");
return true;
}
void WtHftStraDemo::on_entrust(uint32_t localid, bool bSuccess, const char* message, const char* userTag)
{
}
void WtHftStraDemo::on_init(IHftStraCtx* ctx)
{
WTSTickSlice* ticks = ctx->stra_get_ticks(_code.c_str(), _count);
if (ticks)
ticks->release();
//WTSKlineSlice* kline = ctx->stra_get_bars(_code.c_str(), "m5", 30);
//if (kline)
// kline->release();
ctx->stra_sub_ticks(_code.c_str());
_ctx = ctx;
}
void WtHftStraDemo::on_tick(IHftStraCtx* ctx, const char* code, WTSTickData* newTick)
{
if (_code.compare(code) != 0)
return;
if (!_orders.empty())
{
check_orders();
return;
}
if (!_channel_ready)
return;
WTSTickData* curTick = ctx->stra_get_last_tick(code);
if (curTick)
curTick->release();
// actiontime是带毫秒的,要取得分钟,则需要除以10w
uint32_t curMin = newTick->actiontime() / 100000;
if (curMin > _last_calc_time)
{//如果spread上次计算的时候小于当前分钟,则重算spread
//重算晚了以后,更新计算时间
_last_calc_time = curMin;
}
//30秒内不重复计算
uint64_t now = TimeUtils::makeTime(ctx->stra_get_date(), ctx->stra_get_time() * 100000 + ctx->stra_get_secs());//(uint64_t)ctx->stra_get_date()*1000000000 + (uint64_t)ctx->stra_get_time()*100000 + ctx->stra_get_secs();
if(now - _last_entry_time <= _freq * 1000)
{
return;
}
int32_t signal = 0;
double price = newTick->price();
//计算部分
double pxInThry = (newTick->bidprice(0)*newTick->askqty(0) + newTick->askprice(0)*newTick->bidqty(0)) / (newTick->bidqty(0) + newTick->askqty(0));
//理论价格大于最新价
if (pxInThry > price)
{
//正向信号
signal = 1;
}
else if (pxInThry < price)
{
//反向信号
signal = -1;
}
if (signal != 0)
{
double curPos = ctx->stra_get_position(code);
curPos -= _reserved;
WTSCommodityInfo* cInfo = ctx->stra_get_comminfo(code);
if(signal > 0 && curPos <= 0)
{//正向信号,且当前仓位小于等于0
//最新价+2跳下单
double targetPx = price + cInfo->getPriceTick() * _offset;
auto ids = ctx->stra_buy(code, targetPx, _unit, "enterlong");
_mtx_ords.lock();
for( auto localid : ids)
{
_orders.insert(localid);
}
_mtx_ords.unlock();
_last_entry_time = now;
}
else if (signal < 0 && (curPos > 0 || ((!_stock || !decimal::eq(_reserved,0)) && curPos == 0)))
{//反向信号,且当前仓位大于0,或者仓位为0但不是股票,或者仓位为0但是基础仓位有修正
//最新价-2跳下单
double targetPx = price - cInfo->getPriceTick()*_offset;
auto ids = ctx->stra_sell(code, targetPx, _unit, "entershort");
_mtx_ords.lock();
for (auto localid : ids)
{
_orders.insert(localid);
}
_mtx_ords.unlock();
_last_entry_time = now;
}
}
}
void WtHftStraDemo::check_orders()
{
if (!_orders.empty() && _last_entry_time != UINT64_MAX)
{
uint64_t now = TimeUtils::makeTime(_ctx->stra_get_date(), _ctx->stra_get_time() * 100000 + _ctx->stra_get_secs());
if (now - _last_entry_time >= _secs * 1000) //如果超过一定时间没有成交完,则撤销
{
_mtx_ords.lock();
for (auto localid : _orders)
{
_ctx->stra_cancel(localid);
_cancel_cnt++;
_ctx->stra_log_info(fmt::format("Order expired, cancelcnt updated to {}", _cancel_cnt).c_str());
}
_mtx_ords.unlock();
}
}
}
void WtHftStraDemo::on_bar(IHftStraCtx* ctx, const char* code, const char* period, uint32_t times, WTSBarStruct* newBar)
{
}
void WtHftStraDemo::on_trade(IHftStraCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double qty, double price, const char* userTag)
{
}
void WtHftStraDemo::on_position(IHftStraCtx* ctx, const char* stdCode, bool isLong, double prevol, double preavail, double newvol, double newavail)
{
}
void WtHftStraDemo::on_order(IHftStraCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double totalQty, double leftQty, double price, bool isCanceled, const char* userTag)
{
//如果不是我发出去的订单,我就不管了
auto it = _orders.find(localid);
if (it == _orders.end())
return;
//如果已撤销或者剩余数量为0,则清除掉原有的id记录
if(isCanceled || leftQty == 0)
{
_mtx_ords.lock();
_orders.erase(it);
if (_cancel_cnt > 0)
{
_cancel_cnt--;
_ctx->stra_log_info(fmt::format("cancelcnt -> {}", _cancel_cnt).c_str());
}
_mtx_ords.unlock();
}
}
void WtHftStraDemo::on_channel_ready(IHftStraCtx* ctx)
{
double undone = _ctx->stra_get_undone(_code.c_str());
if (!decimal::eq(undone, 0) && _orders.empty())
{
//这说明有未完成单不在监控之中,先撤掉
_ctx->stra_log_info(fmt::format("{}有不在管理中的未完成单 {} 手,全部撤销", _code, undone).c_str());
bool isBuy = (undone > 0);
OrderIDs ids = _ctx->stra_cancel(_code.c_str(), isBuy, undone);
for (auto localid : ids)
{
_orders.insert(localid);
}
_cancel_cnt += ids.size();
_ctx->stra_log_info(fmt::format("cancelcnt -> {}", _cancel_cnt).c_str());
}
_channel_ready = true;
}
void WtHftStraDemo::on_channel_lost(IHftStraCtx* ctx)
{
_channel_ready = false;
}