量化交易之HFT篇 - 高频做市模型源码(.cpp文件)

"""
事先声明, 模型源码仅作参考和交流使用, 不能直接用于实盘
"""
#include "WtHftStraDemo.h"
//#include "../Includes/IHftStraCtx.h"
#include "../WtCore/HftStraBaseCtx.h"

#include "../Includes/WTSVariant.hpp"
#include "../Includes/WTSDataDef.hpp"
#include "../Includes/WTSContractInfo.hpp"

#include "../Share/TimeUtils.hpp"
#include "../Share/decimal.h"


extern const char* FACT_NAME;

/// alpha params
#define OPEN_CLOSE_POSITION_OFFSET_TICKS 2
#define UNIT 1
#define MIDPRICE_OFFSET_TICKS 1
#define ALPHA_TICK_COUNTS 600


WtHftStraDemo::WtHftStraDemo(const char* id): HftStrategy(id)
	, _last_tick(nullptr)
	, _last_scan_time(0)
	, _channel_ready(false)
	, _re_connect_ready(false)
	, _last_mid_price(-1)
	, _current_session_status(DEFAULT_STATUS)
	, _code_buy_lock(false)
	, _code_sell_lock(false)
	, _code_short_lock(false)
	, _code_cover_lock(false)
	, _re_marketMaking(true)
	, _ticks_uptr(make_unique<Ticks>())
{
	this->_commoditiesDocument = this->__tqz_loadJsonDocument("commodities.json");
	this->_sessionsDocument = this->__tqz_loadJsonDocument("sessions.json");
}

WtHftStraDemo::~WtHftStraDemo() {
	if (_last_tick)
		_last_tick->release();
	
	this->_ticks_uptr.reset();

	this->__tqz_cancelAllOrders();
}

const char* WtHftStraDemo::getName() {
	return "HftDemoStrategy";
}

const char* WtHftStraDemo::getFactName() {
	return FACT_NAME;
}

bool WtHftStraDemo::init(WTSVariant* cfg) {
	this->_code = cfg->getCString("code");

	this->_marketMaking_scan_interval = cfg->getUInt32("market_making_scan_interval");

	this->_long_order_offset = cfg->getUInt32("long_order_offset");
	this->_short_order_offset = cfg->getUInt32("short_order_offset");

	this->_offset_open_minutes = cfg->getUInt32("offset_open_minutes");
	this->_offset_close_minutes = cfg->getUInt32("offset_close_minutes");

	this->_record_hft_log = cfg->getBoolean("record_hft_log");

	this->_cancel_limit_counts = cfg->getUInt32("cancel_limit_counts");

	return true;
}

void WtHftStraDemo::on_init(HftStraBaseCtx* ctx) {

	ctx->stra_sub_ticks(_code.c_str());
	
	this->_ctx = ctx;
}

void WtHftStraDemo::on_tick(HftStraBaseCtx* ctx, const char* code, WTSTickData* newTick) {
	if (0 != this->_code.compare(code))
		return;
	if (!this->__isTradingTime(code))
		return;
	if (!this->_channel_ready)
		return;
	if (!this->_re_connect_ready) {
		if (!this->__isNewScanInterval(this->_marketMaking_scan_interval))
			return;

		/// query re_connect_ready & do reconnect.
		this->_re_connect_ready = this->__tqz_queryReconnectResult();
		if (!this->_re_connect_ready)
			this->tqz_doReconnect();

		return;
	}
	if (!this->updateTicks(*newTick))
		return;

	
	if (this->__isClosePositionsTime(code)) {
		if (this->_current_session_status != CLOSE_POSTIONS_STATUS)
			this->__initSessionStatus(CLOSE_POSTIONS_STATUS);
		if (!this->__isNewScanInterval(this->_marketMaking_scan_interval))
			return;

		if (this->__marketMakingIsLock(true))
			return;
		if (this->__closeCodeIsLock(true))
			return;

		this->tqz_closePositions(this->_code, OPEN_CLOSE_POSITION_OFFSET_TICKS);
	} else {
		if (this->_current_session_status != MARKET_MAKING_STATUS)
			this->__initSessionStatus(MARKET_MAKING_STATUS);

		if (this->__closeCodeIsLock(true))
			return;

		/// scan only new time slice.
		if (!this->__isNewScanInterval(this->_marketMaking_scan_interval))
			return;
		if (!this->__midPriceIsChange(MIDPRICE_OFFSET_TICKS))
			return;
		
		/// do market making with time slice.
		if (this->_re_marketMaking) {
			this->tqz_marketMaking(this->getLongOffsetValue(), this->getShortOffsetValue());
			this->_re_marketMaking = !this->_re_marketMaking;
		} else {
			this->__marketMakingIsLock(true);
		}
		
	}
}


int32_t WtHftStraDemo::totalAlphasValue(TicksUPtr& ticksUPtr) {
	int32_t maAlphaValue = MaAlpha::alphaValue(ticksUPtr, 20);
	/*int32_t macdAlphaValue = MacdAlpha::alphaValue(ticksUPtr, 9, 12, 26);
	int32_t diffAlphaValue = DiffAlpha::alphaValue(ticksUPtr, 20);
	int32_t lastTradedQuantityAlphaValue = LastTradedQuantityAlpha::alphaValue(ticksUPtr, 20);
	int32_t bookAlphaValue = BookAlpha::alphaValue(ticksUPtr, 20);*/

	/*
	/// output all values to terminal for test...
	std::cout << "-------------------------------------------" << std::endl;
	//std::cout << "maAlphaValue: " << maAlphaValue << std::endl;
	std::cout << "macdAlphaValue: " << macdAlphaValue << std::endl;
	//std::cout << "diffAlphaValue: " << diffAlphaValue << std::endl;
	std::cout << "lastTradedQuantityAlphaValue: " << lastTradedQuantityAlphaValue << std::endl;
	//std::cout << "bookAlphaValue: " << bookAlphaValue << std::endl;
	std::cout << "-------------------------------------------" << std::endl;
	*/

	//return (maAlphaValue + macdAlphaValue + diffAlphaValue + lastTradedQuantityAlphaValue + bookAlphaValue);
	return maAlphaValue;
}

uint32_t WtHftStraDemo::getLongOffsetValue() {
	int32_t totalAlphasValue = this->totalAlphasValue(this->_ticks_uptr);

	return (totalAlphasValue < 0) ? this->_long_order_offset : (this->_long_order_offset + totalAlphasValue);
}

uint32_t WtHftStraDemo::getShortOffsetValue() {
	int32_t totalAlphasValue = this->totalAlphasValue(this->_ticks_uptr);

	return (totalAlphasValue < 0) ? this->_short_order_offset : (this->_short_order_offset + totalAlphasValue);
}


bool WtHftStraDemo::updateTicks(WTSTickData tickData) {
	if (this->_ticks_uptr->size() == ALPHA_TICK_COUNTS)
		this->_ticks_uptr->erase(this->_ticks_uptr->begin());

	this->_ticks_uptr->push_back(tickData);

	return (this->_ticks_uptr->size() == ALPHA_TICK_COUNTS);
}



void WtHftStraDemo::on_trade(HftStraBaseCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double qty, double price, const char* userTag) {
	if (this->__isBelongToHft(localid)) { // localid is code
		this->__tqz_receiveCodeOnlyCloseCode(localid, this->_code, qty);
	} else {
		/// this->_ctx->stra_log_text("[WtHftStraDemo::on_trade], localid(%d) is not belong to hft strategy(%s)", localid, stdCode);
	}

	this->__tqz_writeStrategyTradeLog(localid, price, qty);
}

void WtHftStraDemo::on_order(HftStraBaseCtx* ctx, uint32_t localid, const char* stdCode, bool isBuy, double totalQty, double leftQty, double price, bool isCanceled, const char* userTag) { // 下单成功后调用
	if (0 != this->_code.compare(stdCode))
		return;
	if (!isCanceled) // order is not cancel.
		return;

	TQZOrderType orderType = this->__tqz_getOrderType(localid); // get order type first.
	if (this->__isBelongToHft(localid)) { // localid is inside.

		switch (orderType) {
			case BUY_TYPE: {
				this->__unlockBuy();
				this->tqz_marketMaking(this->getLongOffsetValue(), this->getShortOffsetValue());
				break;
			}
			case SELL_TYPE: {
				std::string orderComment(this->_re_connect_ready ? "code_sellOrder_reSend" : "code_sellOrder_reConnect_reSend");

				if (this->_code_sell_lock) // re send code sell order.
					this->tqz_sell(this->_code, UNIT, OPEN_CLOSE_POSITION_OFFSET_TICKS, orderComment.c_str());

				break;
			}
			case SHORT_TYPE: {
				this->__unlockShort();
				this->tqz_marketMaking(this->getLongOffsetValue(), this->getShortOffsetValue());
				break;
			}
			case COVER_TYPE: {
				std::string orderComment(this->_re_connect_ready ? "code_coverOrder_reSend" : "code_coverOrder_reConnect_reSend");

				if (this->_code_cover_lock) // re send code cover order.
					this->tqz_cover(this->_code, UNIT, OPEN_CLOSE_POSITION_OFFSET_TICKS, orderComment.c_str());

				break;
			}
			default:
				break;
		}

	} else {
		this->_ctx->stra_log_text("[WtHftStraDemo::on_order] localid is not code, stdCode: %s, localid: %d", stdCode, localid);
	}

}


void WtHftStraDemo::on_channel_ready(HftStraBaseCtx* ctx) {
	std::cout << "HFT_strategy code: " << this->_code << "\n\n" << std::endl;
	
	this->_tradeChange_log_filename = this->__tqz_getLogFileName(TRADE_CHANGE_TYPE);

	this->_channel_ready = true;
	this->__initSessionStatus(RE_CONNECT_STATUS);
}

void WtHftStraDemo::on_entrust(uint32_t localid, bool bSuccess, const char* message, const char* userTag) {
	this->_ctx->stra_log_text("WtHftStraDemo::on_entrust  bSuccess: %d, message: %s\n\n", bSuccess, message);

	TQZOrderType orderType = this->__tqz_getOrderType(localid);
	switch (orderType) {
		case BUY_TYPE:
			this->__unlockBuy();
			break;
		case SELL_TYPE:
			this->__unlockSell();
			break;
		case SHORT_TYPE:
			this->__unlockShort();
			break;
		case COVER_TYPE:
			this->__unlockCover();
			break;
		default:
			break;
	}
}

void WtHftStraDemo::on_channel_lost(HftStraBaseCtx* ctx) {
	this->_channel_ready = false;
}

void WtHftStraDemo::on_bar(HftStraBaseCtx* ctx, const char* code, const char* period, uint32_t times, WTSBarStruct* newBar) {

}

void WtHftStraDemo::on_position(HftStraBaseCtx* ctx, const char* stdCode, bool isLong, double prevol, double preavail, double newvol, double newavail) {

}


void WtHftStraDemo::tqz_buy(const std::string code, const double lots, const int offsetTicks, const std::string orderComment) {
	if (!this->__isEntrustable(code))
		return;

	this->__lockBuy();

	// send buy order & update local var.
	double buyOrderPrice = this->__tqz_getLongPrice(code, offsetTicks);
	uint32_t buyOrderLocalid = this->_ctx->stra_enter_long(code.c_str(), buyOrderPrice, lots, orderComment.c_str());
	std::string currentMarketTimeString = this->__tqz_getCurrentMarketTime();
	std::string sendOrderTimeString = this->__tqz_getCurrentTime();
	this->_code_buy_order = buyOrderLocalid;
	this->_code_buy_orders.insert(buyOrderLocalid);

	if (this->_record_hft_log) // recode log or not.
		this->_log_message_map[buyOrderLocalid] = this->__tqz_getNewLogMessage(
			code,
			buyOrderLocalid,
			this->_ctx->stra_get_price(code.c_str()),
			buyOrderPrice,
			"buy_order",
			currentMarketTimeString,
			sendOrderTimeString,
			orderComment
		);
}

void WtHftStraDemo::tqz_sell(const std::string code, const double lots, const int offsetTicks, const std::string orderComment) {
	if (!this->__isEntrustable(code))
		return;
	this->__lockSell();

	// send sell order & update local var.
	double sellOrderPrice = this->__tqz_getShortPrice(code, offsetTicks);
	uint32_t sellOrderLocalid = this->_ctx->stra_exit_long(code.c_str(), sellOrderPrice, lots, orderComment.c_str(), true);
	std::string currentMarketTimeString = this->__tqz_getCurrentMarketTime();
	std::string sendOrderTimeString = this->__tqz_getCurrentTime();
	this->_code_sell_order = sellOrderLocalid;
	this->_code_sell_orders.insert(sellOrderLocalid);

	if (this->_record_hft_log) // recode log or not.
		this->_log_message_map[sellOrderLocalid] = this->__tqz_getNewLogMessage(
			code,
			sellOrderLocalid,
			this->_ctx->stra_get_price(code.c_str()),
			sellOrderPrice,
			"sell_order",
			currentMarketTimeString,
			sendOrderTimeString,
			orderComment
		);
}

void WtHftStraDemo::tqz_short(const std::string code, const double lots, const int offsetTicks, const std::string orderComment) {
	if (!this->__isEntrustable(code))
		return;

	this->__lockShort();

	double shortOrderPrice = this->__tqz_getShortPrice(code, offsetTicks);
	uint32_t shortOrderLocalid = this->_ctx->stra_enter_short(code.c_str(), shortOrderPrice, lots, orderComment.c_str());
	std::string currentMarketTimeString = this->__tqz_getCurrentMarketTime();
	std::string sendOrderTimeString = this->__tqz_getCurrentTime();
	this->_code_short_order = shortOrderLocalid;
	this->_code_short_orders.insert(shortOrderLocalid);

	if (this->_record_hft_log) // recode log or not.
		this->_log_message_map[shortOrderLocalid] = this->__tqz_getNewLogMessage(
			code,
			shortOrderLocalid,
			this->_ctx->stra_get_price(code.c_str()),
			shortOrderPrice,
			"short_order",
			currentMarketTimeString,
			sendOrderTimeString,
			orderComment
		);
}

void WtHftStraDemo::tqz_cover(const std::string code, const double lots, const int offsetTicks, const std::string orderComment) {
	if (!this->__isEntrustable(code))
		return;

	this->__lockCover();

	// send cover order & update local var.
	double coverOrderPrice = this->__tqz_getLongPrice(code, offsetTicks);
	uint32_t coverOrderLocalid = this->_ctx->stra_exit_short(code.c_str(), coverOrderPrice, lots, orderComment.c_str(), true);
	std::string currentMarketTimeString = this->__tqz_getCurrentMarketTime();
	std::string sendOrderTimeString = this->__tqz_getCurrentTime();
	this->_code_cover_order = coverOrderLocalid;
	this->_code_cover_orders.insert(coverOrderLocalid);

	if (this->_record_hft_log) // recode log or not.
		this->_log_message_map[coverOrderLocalid] = this->__tqz_getNewLogMessage(
			code,
			coverOrderLocalid,
			this->_ctx->stra_get_price(code.c_str()),
			coverOrderPrice,
			"cover_order",
			currentMarketTimeString,
			sendOrderTimeString,
			orderComment
		);
}

void WtHftStraDemo::tqz_marketMaking(const int codeLongOffsetTicks, const int codeShortOffsetTicks) {
	if (!this->__isMarketMakingAble())
		return;

	this->__lockBuy(); // lock market_making.
	this->__lockShort();

	std::string buyOrderComment("code_buyOrder_marketMaking");
	std::string shortOrderComment("code_shortOrder_marketMaking");

	double currentMidPrice = this->_last_mid_price; // make sure mid price of market making is same.
	double buyOrderPrice = this->__tqz_getMarketMakingLongPrice(this->_code.c_str(), currentMidPrice, codeLongOffsetTicks);
	double shortOrderPrice = this->__tqz_getMarketMakingShortPrice(this->_code.c_str(), currentMidPrice, codeShortOffsetTicks);

	uint32_t buyOrderLocalid = this->_ctx->stra_enter_long(this->_code.c_str(), buyOrderPrice, UNIT, buyOrderComment.c_str());
	uint32_t shortOrderLocalid = this->_ctx->stra_enter_short(this->_code.c_str(), shortOrderPrice, UNIT, shortOrderComment.c_str());
	std::string currentMarketTimeString = this->__tqz_getCurrentMarketTime();
	std::string sendOrderTimeString = this->__tqz_getCurrentTime();
	this->_code_buy_order = buyOrderLocalid;
	this->_code_buy_orders.insert(buyOrderLocalid);
	this->_code_short_order = shortOrderLocalid;
	this->_code_short_orders.insert(shortOrderLocalid);

	if (!this->_record_hft_log)
		return;
	double currentPrice = this->_ctx->stra_get_price(this->_code.c_str()); // current market price.
	this->_log_message_map[buyOrderLocalid] = this->__tqz_getNewLogMessage(this->_code, buyOrderLocalid, currentPrice, buyOrderPrice, "buy_order", currentMarketTimeString, sendOrderTimeString, buyOrderComment);
	this->_log_message_map[shortOrderLocalid] = this->__tqz_getNewLogMessage(this->_code, shortOrderLocalid, currentPrice, shortOrderPrice, "short_order", currentMarketTimeString, sendOrderTimeString, shortOrderComment);
}

void WtHftStraDemo::tqz_closePositions(const std::string code, const uint32_t closePositionsOffsetTicks) {

	if (this->_ctx->tqz_getLongPosition(code.c_str()) > 0) { /// close long positions.
		this->tqz_sell(code, UNIT, closePositionsOffsetTicks, "code_sellOrder_closePositions");
	} else if (this->_ctx->tqz_getShortPosition(code.c_str()) > 0) { /// close short positions.
		this->tqz_cover(code, UNIT, closePositionsOffsetTicks, "code_coverOrder_closePositions");
	}
}

void WtHftStraDemo::tqz_doReconnect() {
	if (this->__closeCodeIsLock(true))
		return;

	double currentCodeLongLots = this->_ctx->tqz_getLongPosition(this->_code.c_str());
	double currentCodeShortLots = this->_ctx->tqz_getShortPosition(this->_code.c_str());
	if (currentCodeLongLots > 0 && currentCodeLongLots >= currentCodeShortLots) { /// have long position & long lots big.
		this->tqz_sell(this->_code, UNIT, OPEN_CLOSE_POSITION_OFFSET_TICKS, "code_sellOrder_reConnect");
	} else if (currentCodeShortLots > 0 && currentCodeLongLots < currentCodeShortLots) { /// have short position & short lots big.
		this->tqz_cover(this->_code, UNIT, OPEN_CLOSE_POSITION_OFFSET_TICKS, "code_coverOrder_reConnect");
	}
}

bool WtHftStraDemo::__isEntrustable(std::string code) {
	if (this->__isBeyondUpperlimitOrLowerlimit(code, OPEN_CLOSE_POSITION_OFFSET_TICKS, OPEN_CLOSE_POSITION_OFFSET_TICKS)) /// because cancel limit is 100.
		return false;
	if (this->_ctx->tqz_getCancelCounts(code.c_str()) > (this->_cancel_limit_counts + 10)) {
		this->_ctx->stra_log_text("[WtHftStraDemo::__isEntrustable], out of cancel limit counts when entrust, code: %s, 如果这条log被记录了, 说明策略执行逻辑被强行干扰了", code.c_str());
		return false;
	}

	return true;
}


void WtHftStraDemo::__initSessionStatus(TQZSessionStatus sessionStatus) {

	this->_current_session_status = sessionStatus;

	switch (sessionStatus) {
		case CLOSE_POSTIONS_STATUS: {
			break;
		}
		case MARKET_MAKING_STATUS: { // position and order is empty in theory.
			this->__unlockAllOrders();
			this->__tqz_clearPreviousSessionCache();

			this->_re_marketMaking = true;

			break;
		}
		case RE_CONNECT_STATUS: {
			this->__tqz_writeCancelOrderCountsLog(this->_code);

			this->_re_connect_ready = this->__tqz_queryReconnectResult();
		}
		default:
			break;
	}
}


bool WtHftStraDemo::__tqz_queryReconnectResult() {
	double codeLongLots = this->_ctx->tqz_getLongPosition(this->_code.c_str());
	double codeShortLots = this->_ctx->tqz_getShortPosition(this->_code.c_str());

	return (codeLongLots < 0.00001 && codeShortLots < 0.00001); // hold positions is empty.
}

void WtHftStraDemo::__tqz_clearPreviousSessionCache() {

	// 缓存清理无效, 成员变量换成指针类型; (每小节初始化时清理一次)
	this->_code_buy_orders.erase(this->_code_buy_orders.begin(), this->_code_buy_orders.end());
	this->_code_sell_orders.erase(this->_code_sell_orders.begin(), this->_code_sell_orders.end());
	this->_code_short_orders.erase(this->_code_short_orders.begin(), this->_code_short_orders.end());
	this->_code_cover_orders.erase(this->_code_cover_orders.begin(), this->_code_cover_orders.end());

	this->_log_message_map.clear();
}

void WtHftStraDemo::__tqz_cancelOrder(const std::string code, const uint32_t orderId) {
	if (this->_ctx->tqz_getCancelCounts(code.c_str()) > (this->_cancel_limit_counts + 15)) {
		this->_ctx->stra_log_text("[WtHftStraDemo::__tqz_cancelOrder] out of cancel limit counts when cancel order, code: %s, orderId: %d, 如果这条log被记录了, 说明策略执行逻辑被强行干扰了", code.c_str(), orderId);
		return;
	}

	this->_ctx->stra_cancel(orderId);
}

void WtHftStraDemo::__tqz_cancelOrders(const std::string code, const IDSet orderIds) {
	for (auto& localid : orderIds)
		this->__tqz_cancelOrder(code, localid);
}

void WtHftStraDemo::__tqz_cancelAllOrders() {
	this->__tqz_cancelOrders(this->_code, this->_code_buy_orders);
	this->__tqz_cancelOrders(this->_code, this->_code_sell_orders);
	this->__tqz_cancelOrders(this->_code, this->_code_short_orders);
	this->__tqz_cancelOrders(this->_code, this->_code_cover_orders);
}

TQZOrderType WtHftStraDemo::__tqz_getOrderType(const uint32_t orderId) {

	TQZOrderType orderType = DEFAULT_ORDER_TYPE;
	if (this->_code_buy_orders.find(orderId) != std::end(this->_code_buy_orders)) {
		orderType = BUY_TYPE;
	} else if (this->_code_sell_orders.find(orderId) != std::end(this->_code_sell_orders)) {
		orderType = SELL_TYPE;
	} else if (this->_code_short_orders.find(orderId) != std::end(this->_code_short_orders)) {
		orderType = SHORT_TYPE;
	} else if (this->_code_cover_orders.find(orderId) != std::end(this->_code_cover_orders)) {
		orderType = COVER_TYPE;
	} else {
		orderType = NO_TYPE;
	}

	return orderType;
}

double WtHftStraDemo::__tqz_getAskPrice(const std::string code) {
	return this->_ctx->stra_get_last_tick(code.c_str())->askprice(0);
}

double WtHftStraDemo::__tqz_getBidPrice(const std::string code) {
	return this->_ctx->stra_get_last_tick(code.c_str())->bidprice(0);
}

double WtHftStraDemo::__tqz_getCurrentMidPrice(const std::string code) {
	return (this->__tqz_getAskPrice(code) + this->__tqz_getBidPrice(code)) * 0.5;
}

bool WtHftStraDemo::__midPriceIsChange(int offsetTicks) {
	double currentMidPrice = this->__tqz_getCurrentMidPrice(this->_code);
	
	double minPriceTick = this->_ctx->stra_get_comminfo(this->_code.c_str())->getPriceTick();
	double midPriceOffset = abs(currentMidPrice - this->_last_mid_price);

	bool midPriceIsChange = (midPriceOffset >= (minPriceTick * offsetTicks));
	if (midPriceIsChange)
		this->_last_mid_price = currentMidPrice;
		
	return midPriceIsChange;
}

double WtHftStraDemo::__tqz_getLowerlimitPrice(const std::string code) {
	return this->_ctx->stra_get_last_tick(code.c_str())->lowerlimit();
}

double WtHftStraDemo::__tqz_getUpperlimitPrice(const std::string code) {
	return this->_ctx->stra_get_last_tick(code.c_str())->upperlimit();
}

double WtHftStraDemo::__tqz_getMarketMakingLongPrice(const std::string code, const double currentMidPrice, const int offsetTicks) {

	double minPriceTick = this->_ctx->stra_get_comminfo(code.c_str())->getPriceTick();
	double marketMakerLongOrderPrice = currentMidPrice - minPriceTick * offsetTicks;

	int longOrderPriceTicks = static_cast<int>(floor(marketMakerLongOrderPrice / minPriceTick));

	return longOrderPriceTicks * minPriceTick;
}

double WtHftStraDemo::__tqz_getMarketMakingShortPrice(const std::string code, const double currentMidPrice, const int offsetTicks) {
	double minPriceTick = this->_ctx->stra_get_comminfo(code.c_str())->getPriceTick();
	double marketMakerShortOrderPrice = currentMidPrice + minPriceTick * offsetTicks;
	
	int shortOrderPriceTicks = static_cast<int>(ceil(marketMakerShortOrderPrice / minPriceTick));

	return shortOrderPriceTicks * minPriceTick;
}

bool WtHftStraDemo::__isBeyondUpperlimitOrLowerlimit(const string code, const int longOrderOffsetTicks, const int shortOrderOffsetTicks) {

	if (this->__tqz_getLongPrice(code, longOrderOffsetTicks) >= this->__tqz_getUpperlimitPrice(code))
		return true;
	if (this->__tqz_getShortPrice(code, shortOrderOffsetTicks) <= this->__tqz_getLowerlimitPrice(code))
		return true;

	return false;
}

double WtHftStraDemo::__tqz_getLongPrice(const std::string code, const int offsetTicks = 0) {

	WTSCommodityInfo* codeInfo = this->_ctx->stra_get_comminfo(code.c_str());

	double longPrice = this->__tqz_getAskPrice(code.c_str()) + codeInfo->getPriceTick() * offsetTicks;

	if (longPrice >= this->__tqz_getUpperlimitPrice(code))
		longPrice = this->__tqz_getUpperlimitPrice(code);
	if (longPrice <= this->__tqz_getLowerlimitPrice(code))
		longPrice = this->__tqz_getLowerlimitPrice(code);

	return longPrice;
}

double WtHftStraDemo::__tqz_getShortPrice(const std::string code, const int offsetTicks = 0) {

	WTSCommodityInfo* codeInfo = this->_ctx->stra_get_comminfo(code.c_str());

	double shortPrice = this->__tqz_getBidPrice(code) - codeInfo->getPriceTick() * offsetTicks;

	if (shortPrice <= this->__tqz_getLowerlimitPrice(code))
		shortPrice = this->__tqz_getLowerlimitPrice(code);
	if (shortPrice >= this->__tqz_getUpperlimitPrice(code))
		shortPrice = this->__tqz_getUpperlimitPrice(code);

	return shortPrice;
}


void WtHftStraDemo::__tqz_receiveCodeOnlyCloseCode(const uint32_t localid, const std::string code, const double lots) {
	switch (this->__tqz_getOrderType(localid)) {
		case BUY_TYPE: {
			this->__tqz_cancelOrder(code, this->_code_short_order);

			if (this->_ctx->tqz_getLongPosition(code.c_str()) > 0)
				this->tqz_sell(code, lots, OPEN_CLOSE_POSITION_OFFSET_TICKS, "code_sellOrder_onlyClose");

			break;
		} case SELL_TYPE: { // close positions time.
			this->__unlockBuy();
			this->__unlockSell();

			this->_re_marketMaking = true;

			break;
		} case SHORT_TYPE: {
			this->__tqz_cancelOrder(code, this->_code_buy_order);

			if (this->_ctx->tqz_getShortPosition(code.c_str()) > 0)
				this->tqz_cover(code, lots, OPEN_CLOSE_POSITION_OFFSET_TICKS, "code_coverOrder_onlyClose");

			break;
		} case COVER_TYPE: { // close positions time.
			this->__unlockShort();
			this->__unlockCover();

			this->_re_marketMaking = true;

			break;
		}
	}
}

bool WtHftStraDemo::__isBelongToHft(const uint32_t orderId) {

	bool isBelongToHft = false;
	if (this->_code_buy_orders.find(orderId) != std::end(this->_code_buy_orders)) {
		isBelongToHft = true;
	} else if (this->_code_sell_orders.find(orderId) != std::end(this->_code_sell_orders)) {
		isBelongToHft = true;
	} else if (this->_code_short_orders.find(orderId) != std::end(this->_code_short_orders)) {
		isBelongToHft = true;
	} else if (this->_code_cover_orders.find(orderId) != std::end(this->_code_cover_orders)) {
		isBelongToHft = true;
	}

	return isBelongToHft;
}


int WtHftStraDemo::__tqz_getCurrentHourMinute() {
	struct tm *newtime;
	time_t long_time;
	time(&long_time);
	newtime = localtime(&long_time);

	return newtime->tm_hour * 100 + newtime->tm_min;
}

rapidjson::Document WtHftStraDemo::__tqz_loadJsonDocument(const std::string jsonPath) {
	char readBuffer[65536];

	FILE* filePoint = fopen(jsonPath.c_str(), "r");

	rapidjson::FileReadStream fileStream(filePoint, readBuffer, sizeof(readBuffer));
	rapidjson::Document document;

	document.ParseStream(fileStream);

	fclose(filePoint);

	return document;
}

std::string WtHftStraDemo::__tqz_getSession(const std::string symbolCode) {

	std::vector<std::string> elements;
	std::stringstream stringStream(symbolCode.c_str());
	std::string item;

	int index = 0;
	std::string exchangeString;
	std::string symString;
	std::string symbolYearMonth;
	while (std::getline(stringStream, item, '.')) {
		elements.push_back(item);
		if (index == 0) {
			exchangeString = item;
		} else if (index == 1) {
			symString = item;
		} else if (index == 2) {
			symbolYearMonth = item;
		}
		index++;
	}

	return this->_commoditiesDocument[exchangeString.c_str()][symString.c_str()]["session"].GetString();
}

bool WtHftStraDemo::__isTradingTime(const std::string code) {

	string sessionString = this->__tqz_getSession(code);

	rapidjson::Value& sections = this->_sessionsDocument[sessionString.c_str()]["sections"];
	
	bool tradeable = false;
	if (sections.IsArray() && !sections.Empty()) {

		for (auto& section : sections.GetArray()) {
			if (!section.IsObject()) // type of section is not object.
				continue;
			if (!(section.HasMember("from") && section.HasMember("to"))) // has no from key or to key.
				continue;

			int currentHourMinute = this->__tqz_getCurrentHourMinute();

			if (section["from"].GetInt() <= currentHourMinute && currentHourMinute < section["to"].GetInt()) { // is trading time.
				tradeable = true;
			}
			if (section["from"].GetInt() > section["to"].GetInt()) { // is night trading time.
				if (currentHourMinute >= section["from"].GetInt() || currentHourMinute < section["to"].GetInt()) {
					tradeable = true;
				}
			}
		}
	} else {
		throw exception("result is not array type or empty array");
	}

	return tradeable;
}

bool WtHftStraDemo::__isClosePositionsTime(const std::string code) {

	string sessionString = this->__tqz_getSession(code);

	rapidjson::Value& sections = this->_sessionsDocument[sessionString.c_str()]["sections"];

	bool isClosePositionsTime = false;

	if (sections.IsArray() && !sections.Empty()) {
		for (auto& section : sections.GetArray()) {
			if (!section.IsObject()) // type of section is not object.
				continue;
			if (!(section.HasMember("from") && section.HasMember("to"))) // has no from key or to key.
				continue;

			uint32_t toHourMinute = this->__tqz_resetToHourMinute(section["to"].GetInt(), this->_offset_close_minutes);
			uint32_t currentHourMinute = this->__tqz_getCurrentHourMinute();
			if ((toHourMinute - this->_offset_close_minutes) <= currentHourMinute && currentHourMinute < toHourMinute) // is close positions time.
				isClosePositionsTime = true;
		}
	} else {
		throw exception("result is not array type or empty array");
	}

	return isClosePositionsTime;
}

int WtHftStraDemo::__tqz_resetToHourMinute(int toHourMinute, const int offsetCloseMinutes = 0){
	int toMinute = toHourMinute % 100;
	int toHour = toHourMinute / 100;
	int offsetMinutes = offsetCloseMinutes % 60;
	int offsetHours = offsetCloseMinutes / 60;

	int newMinute = 60 + toMinute; // reset minutes
	int newHour = (toHour - (offsetHours % 24 + 1) + 24) % 24; // reset hours
	if (toMinute - offsetMinutes < 0 || offsetHours != 0) // reset toHourMinute or not
		toHourMinute = newHour * 100 + newMinute;

	return toHourMinute;
}

std::string WtHftStraDemo::__tqz_getLogFileName(const TQZLogFileType logfileType) {

	switch (logfileType) {
		case TRADE_CHANGE_TYPE:
			return "hft_tradeChange_" + to_string(this->_ctx->tqz_getTradingDate());
		case CANCEL_ORDER_COUNTS_TYPE:
			return "hft_cancelOrderCounts_" + to_string(this->_ctx->tqz_getTradingDate());
		default:
			return "";
	}
}

std::string WtHftStraDemo::__tqz_getCurrentTime() {

	const boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
	const boost::posix_time::time_duration timeOfDay = now.time_of_day();

	const uint64_t hours = timeOfDay.hours();
	const uint64_t minutes = timeOfDay.minutes();
	const uint64_t seconds = timeOfDay.seconds();
	const uint64_t milliseconds = timeOfDay.total_milliseconds() - (hours * 3600 + minutes * 60 + seconds) * 1000;

	return this->__tqz_getTimeString(hours, minutes, seconds, milliseconds);
}

std::string WtHftStraDemo::__tqz_getCurrentMarketTime() {

	uint32_t time = this->_ctx->stra_get_time();
	uint32_t secs = this->_ctx->stra_get_secs();

	int hours = time / 100;
	int minutes = time % 100;
	int seconds = secs / 1000;
	int milliseconds = secs % 1000;

	return this->__tqz_getTimeString(hours, minutes, seconds, milliseconds);
}


std::string WtHftStraDemo::__tqz_getTimeString(const uint64_t hours, const uint64_t minutes, const uint64_t seconds, const uint64_t milliseconds) {
	std::string hoursString = to_string(hours);
	if (hours < 10)
		hoursString = "0" + to_string(hours);

	std::string minutesString = to_string(minutes);
	if (minutes < 10)
		minutesString = "0" + to_string(minutes);

	std::string secondsString = to_string(seconds);
	if (seconds < 10)
		secondsString = "0" + to_string(seconds);

	std::string millisecondsString = to_string(milliseconds);
	if (milliseconds < 10) {
		millisecondsString = "00" + to_string(milliseconds);
	} else if (milliseconds < 100) {
		millisecondsString = "0" + to_string(milliseconds);
	}

	return hoursString + ":" + minutesString + ":" + secondsString + "." + millisecondsString;
}


void WtHftStraDemo::__tqz_writeStrategyTradeLog(const uint32_t orderid, const double receiveTradePrice, const double lots) {
	if (this->_log_message_map.find(orderid) == this->_log_message_map.end()) 
		return;

	TQZLogMessage logMessage = this->_log_message_map[orderid];

	std::string logString = "[code|" + logMessage.code + ",order_type|" + logMessage.orderType + ",orderid|" + to_string(logMessage.orderid) + ",market_price_of_send_order|" + to_string(logMessage.currentPrice) + ",market_time_of_send_order|" + logMessage.currentMarketTime + ",send_order_price|" + to_string(logMessage.orderPrice) + ",send_order_time|" + logMessage.sendOrderTime + ",receive_trade_price|" + to_string(receiveTradePrice) + ",receive_trade_time|" + this->__tqz_getCurrentTime() + ",lots|" + to_string(lots) + ",volScale|" + to_string(this->_ctx->stra_get_comminfo(this->_code.c_str())->getVolScale()) + ",order_comment|" + logMessage.orderComment + "]";
	this->_ctx->tqz_writeLog(this->_tradeChange_log_filename, logString);
}

void WtHftStraDemo::__tqz_writeCancelOrderCountsLog(const std::string code) {
	int now = this->__tqz_getCurrentHourMinute();
	if (now < 1500 || now > 1630)
		return;

	uint32_t cancel_order_counts = this->_ctx->tqz_getCancelCounts(code.c_str());

	std::string logString = "[code|" + code + ",cancel_order_counts|" + to_string(cancel_order_counts) + "]";
	this->_ctx->tqz_writeLog(this->__tqz_getLogFileName(CANCEL_ORDER_COUNTS_TYPE), logString);
}

TQZLogMessage WtHftStraDemo::__tqz_getNewLogMessage(std::string code, uint32_t orderid, double currentPrice, double orderPrice, char* orderType, std::string currentMarketTime, std::string sendOrderTime, std::string orderComment) {
	return TQZLogMessage(code, orderid, currentPrice, orderPrice, orderType, currentMarketTime, sendOrderTime, orderComment);
}

uint64_t WtHftStraDemo::__getCurrentTimestamp() {

	const boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
	const boost::posix_time::time_duration timeOfDay = now.time_of_day();
	boost::posix_time::ptime epoch(boost::gregorian::date(1970, boost::gregorian::Jan, 1));
	boost::posix_time::time_duration time_from_epoch = boost::posix_time::second_clock::universal_time() - epoch;

	return time_from_epoch.total_seconds();
}

bool WtHftStraDemo::__isNewScanInterval(const uint32_t scanInterval) {

	uint64_t now = this->__getCurrentTimestamp();
	bool isNew = (now - this->_last_scan_time < scanInterval) ? false : true;

	if (isNew)
		this->_last_scan_time = now;

	return isNew;
}


void WtHftStraDemo::__lockBuy() {
	this->_code_buy_lock = true;
}

void WtHftStraDemo::__lockSell() {
	this->_code_sell_lock = true;
}

void WtHftStraDemo::__lockShort() {
	this->_code_short_lock = true;
}

void WtHftStraDemo::__lockCover() {
	this->_code_cover_lock = true;
}

void WtHftStraDemo::__unlockBuy() {
	this->_code_buy_lock = false;
}

void WtHftStraDemo::__unlockSell() {
	this->_code_sell_lock = false;
}

void WtHftStraDemo::__unlockShort() {
	this->_code_short_lock = false;
}

void WtHftStraDemo::__unlockCover() {
	this->_code_cover_lock = false;
}

void WtHftStraDemo::__unlockAllOrders() {
	this->__unlockBuy();
	this->__unlockSell();
	this->__unlockShort();
	this->__unlockCover();

	this->__unlockBuy();
	this->__unlockSell();
	this->__unlockShort();
	this->__unlockCover();
}


bool WtHftStraDemo::__isMarketMakingAble() {
	if (this->__marketMakingIsLock(false))
		return false;
	if (this->_ctx->tqz_getCancelCounts(this->_code.c_str()) > this->_cancel_limit_counts)
		return false;
	if (this->_current_session_status != MARKET_MAKING_STATUS)
		return false;
	if (this->__isBeyondUpperlimitOrLowerlimit(this->_code, this->_long_order_offset, this->_short_order_offset)) // judge this->_re_market_making is true or false, then modify it...
		return false;

	return true;
}

bool WtHftStraDemo::__closeCodeIsLock(bool reSendLockOrder) {
	bool isLock = (this->_code_sell_lock || this->_code_cover_lock);

	if (!reSendLockOrder)
		return isLock;

	if (this->_code_sell_lock)
		this->__tqz_cancelOrder(this->_code, this->_code_sell_order);
	if (this->_code_cover_lock)
		this->__tqz_cancelOrder(this->_code, this->_code_cover_order);

	return isLock;
}

bool WtHftStraDemo::__marketMakingIsLock(bool cancelLockOrder) {
	bool isLock = !(!this->_code_buy_lock && !this->_code_short_lock);

	if (!cancelLockOrder)
		return isLock;

	if (this->_code_buy_lock)
		this->__tqz_cancelOrder(this->_code, this->_code_buy_order);
	if (this->_code_short_lock)
		this->__tqz_cancelOrder(this->_code, this->_code_short_order);

	return isLock;
}

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值