#include "stdafx.h"
#include "LocalTraderApi.h"
#include "Properties.h"
#include <iostream>
#define READ_CHAR_ARRAY_MEMBER(m) \
{ std::getline(i, temp, ','); \
strncpy(instr.m, temp.c_str(), sizeof(instr.m)); }
#define READ_MEMBER(m) \
{ std::getline(i, temp, ','); \
std::istringstream iss(temp); \
iss >> instr.m; }
#define ADD_TO_TODAY_VALUE(fieldName) todayPos.fieldName += pos.fieldName;
namespace localCTP
{
std::istream& operator>>(std::istream& i, CThostFtdcInstrumentField& instr)
{
std::string temp;
READ_CHAR_ARRAY_MEMBER(InstrumentID)
READ_MEMBER(ExchangeID)
READ_CHAR_ARRAY_MEMBER(InstrumentName)
READ_CHAR_ARRAY_MEMBER(ExchangeInstID)
READ_MEMBER(ProductID)
READ_MEMBER(ProductClass)
READ_MEMBER(DeliveryYear)
READ_MEMBER(DeliveryMonth)
READ_MEMBER(MaxMarketOrderVolume)
READ_MEMBER(MinMarketOrderVolume)
READ_MEMBER(MaxLimitOrderVolume)
READ_MEMBER(MinLimitOrderVolume)
READ_MEMBER(VolumeMultiple)
READ_MEMBER(PriceTick)
READ_MEMBER(CreateDate)
READ_MEMBER(OpenDate)
READ_MEMBER(ExpireDate)
READ_MEMBER(StartDelivDate)
READ_MEMBER(EndDelivDate)
READ_MEMBER(InstLifePhase)
READ_MEMBER(IsTrading)
READ_MEMBER(PositionType)
READ_MEMBER(PositionDateType)
READ_MEMBER(LongMarginRatio)
READ_MEMBER(ShortMarginRatio)
READ_MEMBER(MaxMarginSideAlgorithm)
READ_MEMBER(UnderlyingInstrID)
READ_MEMBER(StrikePrice)
READ_MEMBER(OptionsType)
READ_MEMBER(UnderlyingMultiple)
READ_MEMBER(CombinationType)
return i;
}
CThostFtdcInputOrderField CLocalTraderApi::OrderData::genrateInputOrderFromRtnOrder(
const CThostFtdcOrderField& o)
{
CThostFtdcInputOrderField inputOrder = { 0 };
strncpy(inputOrder.BrokerID, o.BrokerID, sizeof(inputOrder.BrokerID));
strncpy(inputOrder.InvestorID, o.InvestorID, sizeof(inputOrder.InvestorID));
strncpy(inputOrder.OrderRef, o.OrderRef, sizeof(inputOrder.OrderRef));
strncpy(inputOrder.UserID, o.UserID, sizeof(inputOrder.UserID));
inputOrder.OrderPriceType = o.OrderPriceType;
inputOrder.Direction = o.Direction;
strncpy(inputOrder.CombOffsetFlag, o.CombOffsetFlag, sizeof(inputOrder.CombOffsetFlag));
strncpy(inputOrder.CombHedgeFlag, o.CombHedgeFlag, sizeof(inputOrder.CombHedgeFlag));
inputOrder.LimitPrice = o.LimitPrice;
inputOrder.VolumeTotalOriginal = o.VolumeTotalOriginal;
inputOrder.TimeCondition = o.TimeCondition;
strncpy(inputOrder.GTDDate, o.GTDDate, sizeof(inputOrder.GTDDate));
inputOrder.VolumeCondition = o.VolumeCondition;
inputOrder.MinVolume = o.MinVolume;
inputOrder.ContingentCondition = o.ContingentCondition;
inputOrder.StopPrice = o.StopPrice;
inputOrder.ForceCloseReason = o.ForceCloseReason;
inputOrder.IsAutoSuspend = o.IsAutoSuspend;
strncpy(inputOrder.BusinessUnit, o.BusinessUnit, sizeof(inputOrder.BusinessUnit));
inputOrder.RequestID = o.RequestID;
inputOrder.UserForceClose = o.UserForceClose;
inputOrder.IsSwapOrder = o.IsSwapOrder;
strncpy(inputOrder.ExchangeID, o.ExchangeID, sizeof(inputOrder.ExchangeID));
strncpy(inputOrder.InvestUnitID, o.InvestUnitID, sizeof(inputOrder.InvestUnitID));
strncpy(inputOrder.AccountID, o.AccountID, sizeof(inputOrder.AccountID));
strncpy(inputOrder.CurrencyID, o.CurrencyID, sizeof(inputOrder.CurrencyID));
strncpy(inputOrder.ClientID, o.ClientID, sizeof(inputOrder.ClientID));
strncpy(inputOrder.MacAddress, o.MacAddress, sizeof(inputOrder.MacAddress));
strncpy(inputOrder.InstrumentID, o.InstrumentID, sizeof(inputOrder.InstrumentID));
strncpy(inputOrder.IPAddress, o.IPAddress, sizeof(inputOrder.IPAddress));
return inputOrder;
}
CThostFtdcOrderField CLocalTraderApi::OrderData::genrateRtnOrderFromInputOrder(
const CThostFtdcInputOrderField& InputOrder)
{
CThostFtdcOrderField rtnOrder = { 0 };
strncpy(rtnOrder.BrokerID, InputOrder.BrokerID, sizeof(rtnOrder.BrokerID));
strncpy(rtnOrder.InvestorID, InputOrder.InvestorID, sizeof(rtnOrder.InvestorID));
strncpy(rtnOrder.InstrumentID, InputOrder.InstrumentID, sizeof(rtnOrder.InstrumentID));
strncpy(rtnOrder.OrderRef, InputOrder.OrderRef, sizeof(rtnOrder.OrderRef));
strncpy(rtnOrder.UserID, InputOrder.UserID, sizeof(rtnOrder.UserID));
rtnOrder.OrderPriceType = InputOrder.OrderPriceType;
rtnOrder.Direction = InputOrder.Direction;
strncpy(rtnOrder.CombOffsetFlag, InputOrder.CombOffsetFlag, sizeof(rtnOrder.CombOffsetFlag));
strncpy(rtnOrder.CombHedgeFlag, InputOrder.CombHedgeFlag, sizeof(rtnOrder.CombHedgeFlag));
rtnOrder.LimitPrice = InputOrder.LimitPrice;
rtnOrder.VolumeTotalOriginal = InputOrder.VolumeTotalOriginal;
rtnOrder.TimeCondition = InputOrder.TimeCondition;
strncpy(rtnOrder.GTDDate, "", sizeof(rtnOrder.GTDDate));
rtnOrder.VolumeCondition = InputOrder.VolumeCondition;
rtnOrder.MinVolume = InputOrder.MinVolume;
rtnOrder.ContingentCondition = InputOrder.ContingentCondition;
rtnOrder.StopPrice = InputOrder.StopPrice;
rtnOrder.ForceCloseReason = InputOrder.ForceCloseReason;
rtnOrder.IsAutoSuspend = InputOrder.IsAutoSuspend;
strncpy(rtnOrder.BusinessUnit, "", sizeof(rtnOrder.BusinessUnit));
rtnOrder.RequestID = InputOrder.RequestID;
strncpy(rtnOrder.OrderLocalID, InputOrder.OrderRef, sizeof(rtnOrder.OrderLocalID));
strncpy(rtnOrder.ExchangeID, InputOrder.ExchangeID, sizeof(rtnOrder.ExchangeID));
strncpy(rtnOrder.ParticipantID, "", sizeof(rtnOrder.ParticipantID));
strncpy(rtnOrder.ClientID, "", sizeof(rtnOrder.ClientID));
strncpy(rtnOrder.ExchangeInstID, InputOrder.InstrumentID, sizeof(rtnOrder.ExchangeInstID));
strncpy(rtnOrder.TraderID, "", sizeof(rtnOrder.TraderID));
rtnOrder.InstallID = 0;
rtnOrder.OrderSubmitStatus = THOST_FTDC_OSS_InsertSubmitted;
rtnOrder.NotifySequence = 0;
rtnOrder.SettlementID = 0;
strncpy(rtnOrder.OrderSysID, "", sizeof(rtnOrder.OrderSysID));
rtnOrder.OrderSource = THOST_FTDC_OSRC_Participant;
rtnOrder.OrderStatus = THOST_FTDC_OST_Unknown;
rtnOrder.OrderType = THOST_FTDC_ORDT_Normal;
rtnOrder.VolumeTraded = 0;
rtnOrder.VolumeTotal = rtnOrder.VolumeTotalOriginal;
const CLeeDateTime now_time = CLocalTraderApi::getNowTime(); strncpy(rtnOrder.InsertDate, now_time.Format("%Y%m%d").c_str(), sizeof(rtnOrder.InsertDate));
strncpy(rtnOrder.InsertTime, now_time.Format("%H:%M:%S").c_str(), sizeof(rtnOrder.InsertTime));
strncpy(rtnOrder.ActiveTime, "", sizeof(rtnOrder.ActiveTime));
strncpy(rtnOrder.SuspendTime, "", sizeof(rtnOrder.SuspendTime));
strncpy(rtnOrder.UpdateTime, "", sizeof(rtnOrder.UpdateTime));
strncpy(rtnOrder.CancelTime, "", sizeof(rtnOrder.CancelTime));
strncpy(rtnOrder.ActiveTraderID, "", sizeof(rtnOrder.ActiveTraderID));
strncpy(rtnOrder.ClearingPartID, "", sizeof(rtnOrder.ClearingPartID));
rtnOrder.SequenceNo = 0;
strncpy(rtnOrder.UserProductInfo, "", sizeof(rtnOrder.UserProductInfo));
strncpy(rtnOrder.StatusMsg, getStatusMsgByStatus(rtnOrder.OrderStatus).c_str(), sizeof(rtnOrder.StatusMsg));
rtnOrder.UserForceClose = InputOrder.UserForceClose;
strncpy(rtnOrder.ActiveUserID, "", sizeof(rtnOrder.ActiveUserID));
rtnOrder.BrokerOrderSeq = 0;
rtnOrder.ZCETotalTradedVolume = (strcmp(InputOrder.ExchangeID, "CZCE") == 0 ? rtnOrder.VolumeTraded : 0);
rtnOrder.IsSwapOrder = InputOrder.IsSwapOrder;
strncpy(rtnOrder.BranchID, "", sizeof(rtnOrder.BranchID));
strncpy(rtnOrder.InvestUnitID, InputOrder.InvestUnitID, sizeof(rtnOrder.InvestUnitID));
strncpy(rtnOrder.AccountID, InputOrder.AccountID, sizeof(rtnOrder.AccountID));
strncpy(rtnOrder.CurrencyID, "CNY", sizeof(rtnOrder.CurrencyID));
return rtnOrder;
}
bool CLocalTraderApi::OrderData::isDone() const
{
return rtnOrder.OrderStatus != THOST_FTDC_OST_PartTradedQueueing &&
rtnOrder.OrderStatus != THOST_FTDC_OST_NoTradeQueueing &&
rtnOrder.OrderStatus != THOST_FTDC_OST_Unknown &&
rtnOrder.OrderStatus != THOST_FTDC_OST_NotTouched;
}
void CLocalTraderApi::OrderData::dealTestReqOrderInsertNormal(const CThostFtdcInputOrderField& InputOrder,
const std::string& relativeOrderSysID)
{
strncpy(rtnOrder.TradingDay, api.GetTradingDay(), sizeof(rtnOrder.TradingDay));
rtnOrder.FrontID = api.getFrontID();
rtnOrder.SessionID = api.getSessionID();
strncpy(rtnOrder.RelativeOrderSysID, relativeOrderSysID.c_str(), sizeof(rtnOrder.RelativeOrderSysID));
sendRtnOrder();
const auto OrderSysID = api.getNextOrderSysID(InputOrder.ExchangeID);
if (isConditionalOrder)
{
strncpy(rtnOrder.OrderSysID,
(CONDITIONAL_ORDER_SYSID_PREFIX + std::to_string(OrderSysID)).c_str(),
sizeof(rtnOrder.OrderSysID));
rtnOrder.OrderStatus = THOST_FTDC_OST_NotTouched;
}
else
{
strncpy(rtnOrder.OrderSysID, std::to_string(OrderSysID).c_str(),
sizeof(rtnOrder.OrderSysID));
rtnOrder.OrderStatus = THOST_FTDC_OST_NoTradeQueueing;
}
rtnOrder.BrokerOrderSeq = static_cast<TThostFtdcSequenceNoType>(OrderSysID);
rtnOrder.OrderSubmitStatus = THOST_FTDC_OSS_Accepted;
strncpy(rtnOrder.StatusMsg, getStatusMsgByStatus(rtnOrder.OrderStatus).c_str(),
sizeof(rtnOrder.StatusMsg));
sendRtnOrder();
return;
}
void CLocalTraderApi::OrderData::handleTrade(const TradePriceVec& tradedPriceInfo, int tradedSize)
{
if (tradedSize <= 0 || isDone()) return;
rtnOrder.VolumeTraded += tradedSize;
rtnOrder.VolumeTotal -= tradedSize;
rtnOrder.ZCETotalTradedVolume = (strcmp(rtnOrder.ExchangeID, "CZCE") == 0 ? rtnOrder.VolumeTraded : 0);
rtnOrder.OrderSubmitStatus = THOST_FTDC_OSS_Accepted;
if (rtnOrder.VolumeTraded >= rtnOrder.VolumeTotalOriginal)
{
rtnOrder.OrderStatus = THOST_FTDC_OST_AllTraded;
}
else
{
rtnOrder.OrderStatus = THOST_FTDC_OST_PartTradedQueueing;
}
strncpy(rtnOrder.StatusMsg, getStatusMsgByStatus(rtnOrder.OrderStatus).c_str(),
sizeof(rtnOrder.StatusMsg));
std::vector<CThostFtdcTradeFieldWrapper> rtnTradeFromOrder;
getRtnTrade(tradedPriceInfo, tradedSize, rtnTradeFromOrder);
for (auto& t : rtnTradeFromOrder)
{
api.updateByTrade(t); sendRtnTrade(t);
}
rtnTrades.insert(rtnTrades.end(), rtnTradeFromOrder.begin(), rtnTradeFromOrder.end());
sendRtnOrder();
return;
}
void CLocalTraderApi::OrderData::handleCancel(bool cancelFromClient)
{
if (isDone()) return;
rtnOrder.OrderSubmitStatus = THOST_FTDC_OSS_Accepted;
rtnOrder.OrderStatus = THOST_FTDC_OST_Canceled;
strncpy(rtnOrder.StatusMsg, getStatusMsgByStatus(rtnOrder.OrderStatus).c_str(),
sizeof(rtnOrder.StatusMsg));
const CLeeDateTime now_time = CLocalTraderApi::getNowTime(); strncpy(rtnOrder.CancelTime, now_time.Format("%H:%M:%S").c_str(),
sizeof(rtnOrder.CancelTime));
if (cancelFromClient)
{
strncpy(rtnOrder.ActiveUserID, rtnOrder.UserID, sizeof(rtnOrder.ActiveUserID));
}
api.updateByCancel(rtnOrder);
sendRtnOrder();
}
void CLocalTraderApi::OrderData::getRtnTrade(const TradePriceVec& tradePriceVec,
int tradedSize, std::vector<CThostFtdcTradeFieldWrapper>& Trades)
{
std::vector<std::string> SingleContracts;
CLocalTraderApi::GetSingleContractFromCombinationContract(rtnOrder.InstrumentID, SingleContracts);
if (tradePriceVec.size() != SingleContracts.size())
{
return;
}
for (size_t _index = 0; _index != SingleContracts.size(); ++_index)
{
const auto& instr = SingleContracts[_index];
CThostFtdcTradeField Trade = { 0 };
strncpy(Trade.BrokerID, rtnOrder.BrokerID, sizeof(Trade.BrokerID));
strncpy(Trade.InvestorID, rtnOrder.InvestorID, sizeof(Trade.InvestorID));
strncpy(Trade.InstrumentID, instr.c_str(), sizeof(Trade.InstrumentID));
strncpy(Trade.OrderRef, rtnOrder.OrderRef, sizeof(Trade.OrderRef));
strncpy(Trade.UserID, rtnOrder.UserID, sizeof(Trade.UserID));
strncpy(Trade.ExchangeID, rtnOrder.ExchangeID, sizeof(Trade.ExchangeID));
strncpy(Trade.TradeID, std::to_string(api.getNextTradeID(Trade.ExchangeID)).c_str(), sizeof(Trade.TradeID));
if (_index % 2 == 0) {
Trade.Direction = rtnOrder.Direction;
Trade.OffsetFlag = rtnOrder.CombOffsetFlag[0];
}
else {
Trade.Direction = getOppositeDirection(rtnOrder.Direction);
if (rtnOrder.IsSwapOrder == 0) {
Trade.OffsetFlag = rtnOrder.CombOffsetFlag[0];
}
else {
Trade.OffsetFlag = (rtnOrder.CombOffsetFlag[0] == THOST_FTDC_OF_Open ?
THOST_FTDC_OF_Close: THOST_FTDC_OF_Open);
}
}
Trade.Price = tradePriceVec[_index];
strncpy(Trade.OrderSysID, rtnOrder.OrderSysID, sizeof(Trade.OrderSysID));
strncpy(Trade.ParticipantID, rtnOrder.ParticipantID, sizeof(Trade.ParticipantID));
strncpy(Trade.ClientID, rtnOrder.ClientID, sizeof(Trade.ClientID));
Trade.TradingRole = THOST_FTDC_ER_Broker;
strncpy(Trade.ExchangeInstID, Trade.InstrumentID, sizeof(Trade.ExchangeInstID));
Trade.HedgeFlag = rtnOrder.CombHedgeFlag[0];
Trade.Volume = tradedSize;
const CLeeDateTime now_time = CLocalTraderApi::getNowTime(); strncpy(Trade.TradeDate, now_time.Format("%Y%m%d").c_str(), sizeof(Trade.TradeDate));
strncpy(Trade.TradeTime, now_time.Format("%H:%M:%S").c_str(), sizeof(Trade.TradeTime));
Trade.TradeType = SingleContracts.size() == 1 ?
THOST_FTDC_TRDT_Common : THOST_FTDC_TRDT_CombinationDerived;
Trade.PriceSource = THOST_FTDC_PSRC_LastPrice;
strncpy(Trade.TraderID, rtnOrder.TraderID, sizeof(Trade.TraderID));
strncpy(Trade.OrderLocalID, rtnOrder.OrderLocalID, sizeof(Trade.OrderLocalID));
strncpy(Trade.ClearingPartID, "", sizeof(Trade.ClearingPartID));
strncpy(Trade.BusinessUnit, rtnOrder.BusinessUnit, sizeof(Trade.BusinessUnit));
Trade.SequenceNo = rtnOrder.SequenceNo;
strncpy(Trade.TradingDay, rtnOrder.TradingDay, sizeof(Trade.TradingDay));
Trade.SettlementID = rtnOrder.SettlementID;
Trade.BrokerOrderSeq = rtnOrder.BrokerOrderSeq;
Trade.TradeSource = THOST_FTDC_TSRC_NORMAL;
strncpy(Trade.InvestUnitID, rtnOrder.InvestUnitID, sizeof(Trade.InvestUnitID));
Trades.emplace_back(Trade);
}
return;
}
void CLocalTraderApi::OrderData::sendRtnOrder()
{
api.saveOrderToDb(rtnOrder);
api.getMessageQueue().addMsg(OnRtnOrderMsg(&rtnOrder));
}
void CLocalTraderApi::OrderData::sendRtnTrade(CThostFtdcTradeFieldWrapper& rtnTrade)
{
api.saveDataToDb(rtnTrade);
api.getMessageQueue().addMsg(OnRtnTradeMsg(&(rtnTrade.data)));
}
CThostFtdcInvestorPositionDetailField CLocalTraderApi::PositionData::getPositionDetailFromOpenTrade(
const CThostFtdcTradeField& trade)
{
CThostFtdcInvestorPositionDetailField posDetail = { 0 };
if (!isOpen(trade.OffsetFlag)) return posDetail;
strncpy(posDetail.BrokerID, trade.BrokerID, sizeof(posDetail.BrokerID));
strncpy(posDetail.InvestorID, trade.InvestorID, sizeof(posDetail.InvestorID));
strncpy(posDetail.ExchangeID, trade.ExchangeID, sizeof(posDetail.ExchangeID));
strncpy(posDetail.InstrumentID, trade.InstrumentID, sizeof(posDetail.InstrumentID));
posDetail.HedgeFlag = trade.HedgeFlag;
posDetail.OpenPrice = trade.Price;
strncpy(posDetail.TradingDay, trade.TradingDay, sizeof(posDetail.TradingDay));
strncpy(posDetail.OpenDate, trade.TradingDay, sizeof(posDetail.OpenDate));
strncpy(posDetail.TradeID, trade.TradeID, sizeof(posDetail.TradeID));
posDetail.Volume = trade.Volume;
posDetail.Direction = trade.Direction;
posDetail.TradeType = trade.TradeType;
posDetail.CloseVolume = 0;
posDetail.LastSettlementPrice = trade.Price;
return posDetail;
}
void CLocalTraderApi::PositionData::addPositionDetail(
const CThostFtdcInvestorPositionDetailField& posDetail)
{
auto it = std::find_if(posDetailData.begin(), posDetailData.end(),
[&](const CThostFtdcInvestorPositionDetailField& d) {
return (strcmp(d.ExchangeID, posDetail.ExchangeID) == 0 &&
strcmp(d.OpenDate, posDetail.OpenDate) == 0 &&
strcmp(d.TradeID, posDetail.TradeID) == 0);
}
);
if (it == posDetailData.end()) {
posDetailData.push_back(posDetail);
sortPositionDetail(); }
else *it = posDetail;
}
#define ACCUMULATE_WITH_DIFFERENT_NAME(FIELD_NAME1, FIELD_NAME2) #FIELD_NAME1 \
" = IFNULL( ( SELECT SUM(" #FIELD_NAME2 ") FROM CThostFtdcInvestorPositionField " \
" WHERE CThostFtdcInvestorPositionField.InvestorID = CThostFtdcTradingAccountField.AccountID AND " \
" CThostFtdcInvestorPositionField.BrokerID = CThostFtdcTradingAccountField.BrokerID), 0) "
#define ACCUMULATE_WITH_SAME_NAME(FIELD) ACCUMULATE_WITH_DIFFERENT_NAME(FIELD, FIELD)
CSettlementHandler::CSettlementHandler(CSqliteHandler& _sqlHandler)
: m_sqlHandler(_sqlHandler)
, m_running(true)
, m_tradingAccountUpdateFromPositionSql1(
"UPDATE CThostFtdcTradingAccountField SET "
ACCUMULATE_WITH_SAME_NAME(PositionProfit) ", "
ACCUMULATE_WITH_SAME_NAME(CloseProfit) ", "
ACCUMULATE_WITH_SAME_NAME(Commission) ", "
ACCUMULATE_WITH_SAME_NAME(CashIn) ", "
ACCUMULATE_WITH_DIFFERENT_NAME(CurrMargin,UseMargin) ", "
ACCUMULATE_WITH_SAME_NAME(FrozenMargin) ", "
ACCUMULATE_WITH_SAME_NAME(FrozenCommission) ", "
ACCUMULATE_WITH_SAME_NAME(FrozenCash) ";"
)
, m_tradingAccountUpdateFromPositionSql2(
"UPDATE CThostFtdcTradingAccountField SET "
" Balance = PreBalance+Deposit-Withdraw+PositionProfit+CloseProfit-Commission+CashIn;"
)
, m_tradingAccountUpdateFromPositionSql3(
"UPDATE CThostFtdcTradingAccountField SET "
" Available = Balance-CurrMargin-FrozenMargin-FrozenCommission-FrozenCash;"
)
, m_sleepSecond(1)
, m_nextSettlementTime()
, m_count(0)
, m_timerThread([this]() {
std::this_thread::sleep_for(std::chrono::seconds(3)); CLocalTraderApi::initInstrMap();
std::string tradingDay = CLocalTraderApi::StaticGetTradingDay();
m_nextSettlementTime.SetDateTime(
std::stoi(tradingDay.substr(0, 4)), std::stoi(tradingDay.substr(4, 2)),
std::stoi(tradingDay.substr(6, 2)),
std::stoi(CLocalTraderApi::m_settlementTime.substr(0, 2)), std::stoi(CLocalTraderApi::m_settlementTime.substr(3, 2)),
std::stoi(CLocalTraderApi::m_settlementTime.substr(6, 2)));
std::cout << "[LocalCTP] next Settlement Time is " << m_nextSettlementTime.Format() << std::endl;
if (checkSettlement()) {
doSettlement();
}
{
std::lock_guard<std::mutex> lck(s_readyMtx);
s_ready.store(true, std::memory_order_release);
}
s_readyCv.notify_all();
while (m_running)
{
std::this_thread::sleep_for(std::chrono::seconds(m_sleepSecond));
const int checkInterval =
(CLocalTraderApi::m_runningMode == RUNNING_MODE::BACKTEST_MODE ? 10 : (60 * 2));
if (++m_count >= checkInterval / m_sleepSecond) {
m_count = 0;
}
else
{
continue;
}
if (checkSettlement())
{
doSettlement();
if (CLocalTraderApi::m_exitAfterSettlement)
{
std::cout << "It should exit the program after settlement!" << std::endl;
#ifdef _WIN32
std::exit(1);
#else
kill(getpid(), SIGTERM);
#endif
}
}
}
})
{
}
CSettlementHandler::~CSettlementHandler()
{
m_running = false;
if (m_timerThread.joinable())
m_timerThread.join();
}
std::atomic<bool> CSettlementHandler::s_ready{false};
std::mutex CSettlementHandler::s_readyMtx;
std::condition_variable CSettlementHandler::s_readyCv;
void CSettlementHandler::WaitUntilReady()
{
(void)CSettlementHandler::getSettlementHandler(CLocalTraderApi::sqlHandler);
std::unique_lock<std::mutex> lck(s_readyMtx);
s_readyCv.wait(lck, []{ return s_ready.load(std::memory_order_acquire); });
}
}
#ifdef _WIN32
extern "C" __declspec(dllexport) void localctp_wait_until_ready()
#else
extern "C" void localctp_wait_until_ready()
#endif
{
localCTP::CSettlementHandler::WaitUntilReady();
}
namespace localCTP {
bool CSettlementHandler::checkSettlement()
{
const auto nowTime = CLocalTraderApi::getNowTime(); if (!isTradingDay(nowTime))
{
return false;
}
if (nowTime < m_nextSettlementTime)
{
return false;
}
CSqliteHandler::SQL_VALUES sqlValues;
m_sqlHandler.SelectData(
"SELECT * FROM 'SettlementData' where TradingDay='" + nowTime.Format("%Y%m%d") + "';",
sqlValues);
if (sqlValues.empty())
{
return true;
}
return false;
}
void CSettlementHandler::init_format_settlement()
{
static bool bFirstReadFormat = true;
if (bFirstReadFormat)
{
bFirstReadFormat = false;
Properties prop;
std::istringstream istrstr(SETTLEMENT_CONTEXT);
prop.loadProperties(istrstr, '=', false);
format_settlement_header1 = prop.getValue("settlement_header1", std::string());
if (!format_settlement_header1.empty())
{
format_settlement_header1 = format_settlement_header1.substr(1);
}
format_settlement_header2 = prop.getValue("settlement_header2", std::string());
if (!format_settlement_header2.empty())
{
format_settlement_header2 = format_settlement_header2.substr(1);
}
format_settlement_header3 = prop.getValue("settlement_header3", std::string());
if (!format_settlement_header3.empty())
{
format_settlement_header3 = format_settlement_header3.substr(1);
}
format_settlement_header4 = prop.getValue("settlement_header4", std::string());
if (!format_settlement_header4.empty())
{
format_settlement_header4 = format_settlement_header4.substr(1);
}
format_settlement_header5 = prop.getValue("settlement_header5", std::string());
if (!format_settlement_header5.empty())
{
format_settlement_header5 = format_settlement_header5.substr(1);
}
format_settlement_header6 = prop.getValue("settlement_header6", std::string());
if (!format_settlement_header6.empty())
{
format_settlement_header6 = format_settlement_header6.substr(1);
}
format_settlement_header7 = prop.getValue("settlement_header7", std::string());
if (!format_settlement_header7.empty())
{
format_settlement_header7 = format_settlement_header7.substr(1);
}
format_settlement_header8 = prop.getValue("settlement_header8", std::string());
if (!format_settlement_header8.empty())
{
format_settlement_header8 = format_settlement_header8.substr(1);
}
format_settlement_header9 = prop.getValue("settlement_header9", std::string());
if (!format_settlement_header9.empty())
{
format_settlement_header9 = format_settlement_header9.substr(1);
}
format_settlement_header10 = prop.getValue("settlement_header10", std::string());
if (!format_settlement_header10.empty())
{
format_settlement_header10 = format_settlement_header10.substr(1);
}
format_settlement_account_summary1 = prop.getValue("settlement_account_summary1", std::string());
if (!format_settlement_account_summary1.empty())
{
format_settlement_account_summary1 = format_settlement_account_summary1.substr(1);
}
format_settlement_account_summary2 = prop.getValue("settlement_account_summary2", std::string());
if (!format_settlement_account_summary2.empty())
{
format_settlement_account_summary2 = format_settlement_account_summary2.substr(1);
}
format_settlement_account_summary3 = prop.getValue("settlement_account_summary3", std::string());
if (!format_settlement_account_summary3.empty())
{
format_settlement_account_summary3 = format_settlement_account_summary3.substr(1);
}
format_settlement_account_summary4 = prop.getValue("settlement_account_summary4", std::string());
if (!format_settlement_account_summary4.empty())
{
format_settlement_account_summary4 = format_settlement_account_summary4.substr(1);
}
format_settlement_account_summary5 = prop.getValue("settlement_account_summary5", std::string());
if (!format_settlement_account_summary5.empty())
{
format_settlement_account_summary5 = format_settlement_account_summary5.substr(1);
}
format_settlement_account_summary6 = prop.getValue("settlement_account_summary6", std::string());
if (!format_settlement_account_summary6.empty())
{
format_settlement_account_summary6 = format_settlement_account_summary6.substr(1);
}
format_settlement_account_summary7 = prop.getValue("settlement_account_summary7", std::string());
if (!format_settlement_account_summary7.empty())
{
format_settlement_account_summary7 = format_settlement_account_summary7.substr(1);
}
format_settlement_account_summary8 = prop.getValue("settlement_account_summary8", std::string());
if (!format_settlement_account_summary8.empty())
{
format_settlement_account_summary8 = format_settlement_account_summary8.substr(1);
}
format_settlement_account_summary9 = prop.getValue("settlement_account_summary9", std::string());
if (!format_settlement_account_summary9.empty())
{
format_settlement_account_summary9 = format_settlement_account_summary9.substr(1);
}
format_settlement_account_summary10 = prop.getValue("settlement_account_summary10", std::string());
if (!format_settlement_account_summary10.empty())
{
format_settlement_account_summary10 = format_settlement_account_summary10.substr(1);
}
format_settlement_account_summary11 = prop.getValue("settlement_account_summary11", std::string());
if (!format_settlement_account_summary11.empty())
{
format_settlement_account_summary11 = format_settlement_account_summary11.substr(1);
}
format_settlement_account_summary12 = prop.getValue("settlement_account_summary12", std::string());
if (!format_settlement_account_summary12.empty())
{
format_settlement_account_summary12 = format_settlement_account_summary12.substr(1);
}
format_settlement_account_summary13 = prop.getValue("settlement_account_summary13", std::string());
if (!format_settlement_account_summary13.empty())
{
format_settlement_account_summary13 = format_settlement_account_summary13.substr(1);
}
format_settlement_account_summary14 = prop.getValue("settlement_account_summary14", std::string());
if (!format_settlement_account_summary14.empty())
{
format_settlement_account_summary14 = format_settlement_account_summary14.substr(1);
}
format_settlement_account_summary15 = prop.getValue("settlement_account_summary15", std::string());
if (!format_settlement_account_summary15.empty())
{
format_settlement_account_summary15 = format_settlement_account_summary15.substr(1);
}
format_settlement_account_summary16 = prop.getValue("settlement_account_summary16", std::string());
if (!format_settlement_account_summary16.empty())
{
format_settlement_account_summary16 = format_settlement_account_summary16.substr(1);
}
format_settlement_account_summary17 = prop.getValue("settlement_account_summary17", std::string());
if (!format_settlement_account_summary17.empty())
{
format_settlement_account_summary17 = format_settlement_account_summary17.substr(1);
}
format_settlement_deposit_withdrawal_head1 = prop.getValue("settlement_deposit_withdrawal_head1", std::string());
if (!format_settlement_deposit_withdrawal_head1.empty())
{
format_settlement_deposit_withdrawal_head1 = format_settlement_deposit_withdrawal_head1.substr(1);
}
format_settlement_deposit_withdrawal_head2 = prop.getValue("settlement_deposit_withdrawal_head2", std::string());
if (!format_settlement_deposit_withdrawal_head2.empty())
{
format_settlement_deposit_withdrawal_head2 = format_settlement_deposit_withdrawal_head2.substr(1);
}
format_settlement_deposit_withdrawal_head3 = prop.getValue("settlement_deposit_withdrawal_head3", std::string());
if (!format_settlement_deposit_withdrawal_head3.empty())
{
format_settlement_deposit_withdrawal_head3 = format_settlement_deposit_withdrawal_head3.substr(1);
}
format_settlement_deposit_withdrawal_head4 = prop.getValue("settlement_deposit_withdrawal_head4", std::string());
if (!format_settlement_deposit_withdrawal_head4.empty())
{
format_settlement_deposit_withdrawal_head4 = format_settlement_deposit_withdrawal_head4.substr(1);
}
format_settlement_deposit_withdrawal_head5 = prop.getValue("settlement_deposit_withdrawal_head5", std::string());
if (!format_settlement_deposit_withdrawal_head5.empty())
{
format_settlement_deposit_withdrawal_head5 = format_settlement_deposit_withdrawal_head5.substr(1);
}
format_settlement_deposit_withdrawal_single_record1 = prop.getValue("settlement_deposit_withdrawal_single_record1", std::string());
if (!format_settlement_deposit_withdrawal_single_record1.empty())
{
format_settlement_deposit_withdrawal_single_record1 = format_settlement_deposit_withdrawal_single_record1.substr(1);
}
format_settlement_deposit_withdrawal_end1 = prop.getValue("settlement_deposit_withdrawal_end1", std::string());
if (!format_settlement_deposit_withdrawal_end1.empty())
{
format_settlement_deposit_withdrawal_end1 = format_settlement_deposit_withdrawal_end1.substr(1);
}
format_settlement_deposit_withdrawal_end2 = prop.getValue("settlement_deposit_withdrawal_end2", std::string());
if (!format_settlement_deposit_withdrawal_end2.empty())
{
format_settlement_deposit_withdrawal_end2 = format_settlement_deposit_withdrawal_end2.substr(1);
}
format_settlement_deposit_withdrawal_end3 = prop.getValue("settlement_deposit_withdrawal_end3", std::string());
if (!format_settlement_deposit_withdrawal_end3.empty())
{
format_settlement_deposit_withdrawal_end3 = format_settlement_deposit_withdrawal_end3.substr(1);
}
format_settlement_deposit_withdrawal_end4 = prop.getValue("settlement_deposit_withdrawal_end4", std::string());
if (!format_settlement_deposit_withdrawal_end4.empty())
{
format_settlement_deposit_withdrawal_end4 = format_settlement_deposit_withdrawal_end4.substr(1);
}
format_settlement_deposit_withdrawal_end5 = prop.getValue("settlement_deposit_withdrawal_end5", std::string());
if (!format_settlement_deposit_withdrawal_end5.empty())
{
format_settlement_deposit_withdrawal_end5 = format_settlement_deposit_withdrawal_end5.substr(1);
}
format_settlement_trade_head1 = prop.getValue("settlement_trade_head1", std::string());
if (!format_settlement_trade_head1.empty())
{
format_settlement_trade_head1 = format_settlement_trade_head1.substr(1);
}
format_settlement_trade_head2 = prop.getValue("settlement_trade_head2", std::string());
if (!format_settlement_trade_head2.empty())
{
format_settlement_trade_head2 = format_settlement_trade_head2.substr(1);
}
format_settlement_trade_head3 = prop.getValue("settlement_trade_head3", std::string());
if (!format_settlement_trade_head3.empty())
{
format_settlement_trade_head3 = format_settlement_trade_head3.substr(1);
}
format_settlement_trade_head4 = prop.getValue("settlement_trade_head4", std::string());
if (!format_settlement_trade_head4.empty())
{
format_settlement_trade_head4 = format_settlement_trade_head4.substr(1);
}
format_settlement_trade_head5 = prop.getValue("settlement_trade_head5", std::string());
if (!format_settlement_trade_head5.empty())
{
format_settlement_trade_head5 = format_settlement_trade_head5.substr(1);
}
format_settlement_trade_single_record1 = prop.getValue("settlement_trade_single_record1", std::string());
if (!format_settlement_trade_single_record1.empty())
{
format_settlement_trade_single_record1 = format_settlement_trade_single_record1.substr(1);
}
format_settlement_trade_end1 = prop.getValue("settlement_trade_end1", std::string());
if (!format_settlement_trade_end1.empty())
{
format_settlement_trade_end1 = format_settlement_trade_end1.substr(1);
}
format_settlement_trade_end2 = prop.getValue("settlement_trade_end2", std::string());
if (!format_settlement_trade_end2.empty())
{
format_settlement_trade_end2 = format_settlement_trade_end2.substr(1);
}
format_settlement_trade_end3 = prop.getValue("settlement_trade_end3", std::string());
if (!format_settlement_trade_end3.empty())
{
format_settlement_trade_end3 = format_settlement_trade_end3.substr(1);
}
format_settlement_trade_end4 = prop.getValue("settlement_trade_end4", std::string());
if (!format_settlement_trade_end4.empty())
{
format_settlement_trade_end4 = format_settlement_trade_end4.substr(1);
}
format_settlement_trade_end5 = prop.getValue("settlement_trade_end5", std::string());
if (!format_settlement_trade_end5.empty())
{
format_settlement_trade_end5 = format_settlement_trade_end5.substr(1);
}
format_settlement_trade_end6 = prop.getValue("settlement_trade_end6", std::string());
if (!format_settlement_trade_end6.empty())
{
format_settlement_trade_end6 = format_settlement_trade_end6.substr(1);
}
format_settlement_trade_end7 = prop.getValue("settlement_trade_end7", std::string());
if (!format_settlement_trade_end7.empty())
{
format_settlement_trade_end7 = format_settlement_trade_end7.substr(1);
}
format_settlement_trade_end8 = prop.getValue("settlement_trade_end8", std::string());
if (!format_settlement_trade_end8.empty())
{
format_settlement_trade_end8 = format_settlement_trade_end8.substr(1);
}
format_settlement_position_closed_head1 = prop.getValue("settlement_position_closed_head1", std::string());
if (!format_settlement_position_closed_head1.empty())
{
format_settlement_position_closed_head1 = format_settlement_position_closed_head1.substr(1);
}
format_settlement_position_closed_head2 = prop.getValue("settlement_position_closed_head2", std::string());
if (!format_settlement_position_closed_head2.empty())
{
format_settlement_position_closed_head2 = format_settlement_position_closed_head2.substr(1);
}
format_settlement_position_closed_head3 = prop.getValue("settlement_position_closed_head3", std::string());
if (!format_settlement_position_closed_head3.empty())
{
format_settlement_position_closed_head3 = format_settlement_position_closed_head3.substr(1);
}
format_settlement_position_closed_head4 = prop.getValue("settlement_position_closed_head4", std::string());
if (!format_settlement_position_closed_head4.empty())
{
format_settlement_position_closed_head4 = format_settlement_position_closed_head4.substr(1);
}
format_settlement_position_closed_head5 = prop.getValue("settlement_position_closed_head5", std::string());
if (!format_settlement_position_closed_head5.empty())
{
format_settlement_position_closed_head5 = format_settlement_position_closed_head5.substr(1);
}
format_settlement_position_closed_single_record1 = prop.getValue("settlement_position_closed_single_record1", std::string());
if (!format_settlement_position_closed_single_record1.empty())
{
format_settlement_position_closed_single_record1 = format_settlement_position_closed_single_record1.substr(1);
}
format_settlement_position_closed_end1 = prop.getValue("settlement_position_closed_end1", std::string());
if (!format_settlement_position_closed_end1.empty())
{
format_settlement_position_closed_end1 = format_settlement_position_closed_end1.substr(1);
}
format_settlement_position_closed_end2 = prop.getValue("settlement_position_closed_end2", std::string());
if (!format_settlement_position_closed_end2.empty())
{
format_settlement_position_closed_end2 = format_settlement_position_closed_end2.substr(1);
}
format_settlement_position_closed_end3 = prop.getValue("settlement_position_closed_end3", std::string());
if (!format_settlement_position_closed_end3.empty())
{
format_settlement_position_closed_end3 = format_settlement_position_closed_end3.substr(1);
}
format_settlement_position_closed_end4 = prop.getValue("settlement_position_closed_end4", std::string());
if (!format_settlement_position_closed_end4.empty())
{
format_settlement_position_closed_end4 = format_settlement_position_closed_end4.substr(1);
}
format_settlement_position_closed_end5 = prop.getValue("settlement_position_closed_end5", std::string());
if (!format_settlement_position_closed_end5.empty())
{
format_settlement_position_closed_end5 = format_settlement_position_closed_end5.substr(1);
}
format_settlement_position_closed_end6 = prop.getValue("settlement_position_closed_end6", std::string());
if (!format_settlement_position_closed_end6.empty())
{
format_settlement_position_closed_end6 = format_settlement_position_closed_end6.substr(1);
}
format_settlement_position_detail_head1 = prop.getValue("settlement_position_detail_head1", std::string());
if (!format_settlement_position_detail_head1.empty())
{
format_settlement_position_detail_head1 = format_settlement_position_detail_head1.substr(1);
}
format_settlement_position_detail_head2 = prop.getValue("settlement_position_detail_head2", std::string());
if (!format_settlement_position_detail_head2.empty())
{
format_settlement_position_detail_head2 = format_settlement_position_detail_head2.substr(1);
}
format_settlement_position_detail_head3 = prop.getValue("settlement_position_detail_head3", std::string());
if (!format_settlement_position_detail_head3.empty())
{
format_settlement_position_detail_head3 = format_settlement_position_detail_head3.substr(1);
}
format_settlement_position_detail_head4 = prop.getValue("settlement_position_detail_head4", std::string());
if (!format_settlement_position_detail_head4.empty())
{
format_settlement_position_detail_head4 = format_settlement_position_detail_head4.substr(1);
}
format_settlement_position_detail_head5 = prop.getValue("settlement_position_detail_head5", std::string());
if (!format_settlement_position_detail_head5.empty())
{
format_settlement_position_detail_head5 = format_settlement_position_detail_head5.substr(1);
}
format_settlement_position_detail_single_record1 = prop.getValue("settlement_position_detail_single_record1", std::string());
if (!format_settlement_position_detail_single_record1.empty())
{
format_settlement_position_detail_single_record1 = format_settlement_position_detail_single_record1.substr(1);
}
format_settlement_position_detail_end1 = prop.getValue("settlement_position_detail_end1", std::string());
if (!format_settlement_position_detail_end1.empty())
{
format_settlement_position_detail_end1 = format_settlement_position_detail_end1.substr(1);
}
format_settlement_position_detail_end2 = prop.getValue("settlement_position_detail_end2", std::string());
if (!format_settlement_position_detail_end2.empty())
{
format_settlement_position_detail_end2 = format_settlement_position_detail_end2.substr(1);
}
format_settlement_position_detail_end3 = prop.getValue("settlement_position_detail_end3", std::string());
if (!format_settlement_position_detail_end3.empty())
{
format_settlement_position_detail_end3 = format_settlement_position_detail_end3.substr(1);
}
format_settlement_position_detail_end4 = prop.getValue("settlement_position_detail_end4", std::string());
if (!format_settlement_position_detail_end4.empty())
{
format_settlement_position_detail_end4 = format_settlement_position_detail_end4.substr(1);
}
format_settlement_position_detail_end5 = prop.getValue("settlement_position_detail_end5", std::string());
if (!format_settlement_position_detail_end5.empty())
{
format_settlement_position_detail_end5 = format_settlement_position_detail_end5.substr(1);
}
format_settlement_position_detail_end6 = prop.getValue("settlement_position_detail_end6", std::string());
if (!format_settlement_position_detail_end6.empty())
{
format_settlement_position_detail_end6 = format_settlement_position_detail_end6.substr(1);
}
format_settlement_position_detail_end7 = prop.getValue("settlement_position_detail_end7", std::string());
if (!format_settlement_position_detail_end7.empty())
{
format_settlement_position_detail_end7 = format_settlement_position_detail_end7.substr(1);
}
format_settlement_position_head1 = prop.getValue("settlement_position_head1", std::string());
if (!format_settlement_position_head1.empty())
{
format_settlement_position_head1 = format_settlement_position_head1.substr(1);
}
format_settlement_position_head2 = prop.getValue("settlement_position_head2", std::string());
if (!format_settlement_position_head2.empty())
{
format_settlement_position_head2 = format_settlement_position_head2.substr(1);
}
format_settlement_position_head3 = prop.getValue("settlement_position_head3", std::string());
if (!format_settlement_position_head3.empty())
{
format_settlement_position_head3 = format_settlement_position_head3.substr(1);
}
format_settlement_position_head4 = prop.getValue("settlement_position_head4", std::string());
if (!format_settlement_position_head4.empty())
{
format_settlement_position_head4 = format_settlement_position_head4.substr(1);
}
format_settlement_position_head5 = prop.getValue("settlement_position_head5", std::string());
if (!format_settlement_position_head5.empty())
{
format_settlement_position_head5 = format_settlement_position_head5.substr(1);
}
format_settlement_position_single_record1 = prop.getValue("settlement_position_single_record1", std::string());
if (!format_settlement_position_single_record1.empty())
{
format_settlement_position_single_record1 = format_settlement_position_single_record1.substr(1);
}
format_settlement_position_end1 = prop.getValue("settlement_position_end1", std::string());
if (!format_settlement_position_end1.empty())
{
format_settlement_position_end1 = format_settlement_position_end1.substr(1);
}
format_settlement_position_end2 = prop.getValue("settlement_position_end2", std::string());
if (!format_settlement_position_end2.empty())
{
format_settlement_position_end2 = format_settlement_position_end2.substr(1);
}
format_settlement_position_end3 = prop.getValue("settlement_position_end3", std::string());
if (!format_settlement_position_end3.empty())
{
format_settlement_position_end3 = format_settlement_position_end3.substr(1);
}
format_settlement_position_end4 = prop.getValue("settlement_position_end4", std::string());
if (!format_settlement_position_end4.empty())
{
format_settlement_position_end4 = format_settlement_position_end4.substr(1);
}
format_settlement_position_end5 = prop.getValue("settlement_position_end5", std::string());
if (!format_settlement_position_end5.empty())
{
format_settlement_position_end5 = format_settlement_position_end5.substr(1);
}
format_settlement_position_end6 = prop.getValue("settlement_position_end6", std::string());
if (!format_settlement_position_end6.empty())
{
format_settlement_position_end6 = format_settlement_position_end6.substr(1);
}
format_settlement_position_end7 = prop.getValue("settlement_position_end7", std::string());
if (!format_settlement_position_end7.empty())
{
format_settlement_position_end7 = format_settlement_position_end7.substr(1);
}
format_settlement_position_end8 = prop.getValue("settlement_position_end8", std::string());
if (!format_settlement_position_end8.empty())
{
format_settlement_position_end8 = format_settlement_position_end8.substr(1);
}
}
return;
}
void CSettlementHandler::accumulateTradingAccountFromPosition()
{
m_sqlHandler.Update(m_tradingAccountUpdateFromPositionSql1);
m_sqlHandler.Update(m_tradingAccountUpdateFromPositionSql2);
m_sqlHandler.Update(m_tradingAccountUpdateFromPositionSql3);
}
void CSettlementHandler::doSettlement()
{
init_format_settlement();
const std::string TradingDay = CLocalTraderApi::StaticGetTradingDay();
std::cout << "[LocalCTP] doSettlement for TradingDay " << TradingDay << std::endl;
doWorkInitialSettlement(TradingDay); CSqliteHandler::SQL_VALUES sqlValues;
m_sqlHandler.SelectData(CThostFtdcTradingAccountFieldWrapper::SELECT_SQL, sqlValues);
for (const auto& userSqlValue : sqlValues)
{
CThostFtdcTradingAccountFieldWrapper tradingAccountFieldWrapper(userSqlValue);
doGenerateUserSettlement(tradingAccountFieldWrapper, TradingDay);
}
const CLeeDateTime dtTradingDay(
std::stoi(TradingDay.substr(0, 4)),
std::stoi(TradingDay.substr(4, 2)),
std::stoi(TradingDay.substr(6, 2)),
0,
0,
0);
const std::string newTradingDay = getNextTradingDay(dtTradingDay);
doWorkAfterSettlement(TradingDay, newTradingDay);
m_nextSettlementTime.SetDateTime(
std::stoi(newTradingDay.substr(0, 4)), std::stoi(newTradingDay.substr(4, 2)),
std::stoi(newTradingDay.substr(6, 2)),
std::stoi(CLocalTraderApi::m_settlementTime.substr(0, 2)), std::stoi(CLocalTraderApi::m_settlementTime.substr(3, 2)),
std::stoi(CLocalTraderApi::m_settlementTime.substr(6, 2)));
return;
}
void CSettlementHandler::doWorkInitialSettlement(
const std::string& oldTradingDay)
{
CSqliteTransactionHandler transactionHandle(m_sqlHandler);
CSqliteHandler::SQL_VALUES posDetailSqlValues;
m_sqlHandler.SelectData(CThostFtdcInvestorPositionDetailFieldWrapper::SELECT_SQL, posDetailSqlValues);
std::vector<CThostFtdcInvestorPositionDetailFieldWrapper> posDetailVec;
for (const auto& rowData : posDetailSqlValues)
{
CThostFtdcInvestorPositionDetailFieldWrapper posDetailWrapper(rowData);
auto& posDetail = posDetailWrapper.data;
auto itInstr = CLocalTraderApi::m_instrData.find(posDetail.InstrumentID);
if (itInstr == CLocalTraderApi::m_instrData.end())
{
continue;
}
auto itMdData = CLocalTraderApi::m_mdData.find(itInstr->second.InstrumentID);
if (itMdData != CLocalTraderApi::m_mdData.end())
{
posDetail.SettlementPrice = itMdData->second.SettlementPrice;
}
if (!isOptions(itInstr->second.ProductClass))
{
const double positionPrice(strcmp(posDetail.OpenDate, posDetail.TradingDay) == 0 ?
posDetail.OpenPrice : posDetail.LastSettlementPrice);
posDetail.PositionProfitByDate = (posDetail.Direction == THOST_FTDC_D_Buy ? 1.0 : -1.0) *
(posDetail.SettlementPrice - positionPrice) *
posDetail.Volume * itInstr->second.VolumeMultiple; posDetail.PositionProfitByTrade = (posDetail.Direction == THOST_FTDC_D_Buy ? 1.0 : -1.0) *
(posDetail.SettlementPrice - posDetail.OpenPrice) *
posDetail.Volume * itInstr->second.VolumeMultiple; }
if (std::string(itInstr->second.ExpireDate) <= oldTradingDay)
{
posDetail.Volume = 0;
}
posDetail.Margin = posDetail.SettlementPrice * posDetail.Volume *
itInstr->second.VolumeMultiple * posDetail.MarginRateByMoney +
posDetail.Volume * posDetail.MarginRateByVolume;
posDetailVec.emplace_back(posDetail);
}
const std::string deletePositionDetailSql = "DELETE FROM CThostFtdcInvestorPositionDetailField;";
m_sqlHandler.Delete(deletePositionDetailSql);
for (auto& posDetail : posDetailVec)
{
m_sqlHandler.Insert(posDetail.generateInsertSql());
}
CSqliteHandler::SQL_VALUES posSqlValues;
m_sqlHandler.SelectData(CThostFtdcInvestorPositionFieldWrapper::SELECT_SQL, posSqlValues);
std::vector<CThostFtdcInvestorPositionFieldWrapper> todayPosVec;
std::vector<CThostFtdcInvestorPositionFieldWrapper> yeterdayPosVec;
for (const auto& rowData : posSqlValues)
{
CThostFtdcInvestorPositionFieldWrapper posWrapper(rowData);
auto& pos = posWrapper.data;
auto itInstr = CLocalTraderApi::m_instrData.find(pos.InstrumentID);
if (itInstr == CLocalTraderApi::m_instrData.end() || itInstr->second.ProductClass == THOST_FTDC_PC_Combination)
{
continue;
}
auto itMdData = CLocalTraderApi::m_mdData.find(itInstr->second.InstrumentID);
if (itMdData != CLocalTraderApi::m_mdData.end())
{
pos.SettlementPrice = itMdData->second.SettlementPrice;
}
if (!isOptions(itInstr->second.ProductClass))
{
pos.PositionProfit = (pos.PosiDirection == THOST_FTDC_PD_Long ? 1.0 : -1.0) *
(pos.SettlementPrice * pos.Position * itInstr->second.VolumeMultiple
- pos.PositionCost); }
if (std::string(itInstr->second.ExpireDate) <= oldTradingDay)
{
if (isOptions(itInstr->second.ProductClass))
{
pos.CashIn += (pos.PosiDirection == THOST_FTDC_PD_Long ? 1.0 : -1.0) *
pos.SettlementPrice * pos.Position * itInstr->second.VolumeMultiple;
}
pos.Position = 0;
}
pos.PositionCost = pos.SettlementPrice * pos.Position *
itInstr->second.VolumeMultiple; pos.UseMargin = pos.PositionCost * pos.MarginRateByMoney +
pos.Position * pos.MarginRateByVolume;
if (pos.PositionDate == THOST_FTDC_PSD_Today)
{
todayPosVec.emplace_back(posWrapper);
}
else
{
yeterdayPosVec.emplace_back(posWrapper);
}
}
for (const auto& yesterdayPos : yeterdayPosVec)
{
const auto& pos = yesterdayPos.data;
const auto relatedTodayPosKey = CLocalTraderApi::generatePositionKey(
pos.InstrumentID,
CLocalTraderApi::getDirectionFromPositionDirection(pos.PosiDirection),
THOST_FTDC_PSD_Today);
auto itTodayPos = std::find_if(todayPosVec.begin(), todayPosVec.end(),
[&](const CThostFtdcInvestorPositionFieldWrapper& p) {
return strcmp(p.data.BrokerID, pos.BrokerID) == 0 &&
strcmp(p.data.InvestorID, pos.InvestorID) == 0 &&
CLocalTraderApi::generatePositionKey(p.data) == relatedTodayPosKey;
});
if (itTodayPos == todayPosVec.end())
{
todayPosVec.emplace_back(yesterdayPos);
}
else
{
auto& todayPos = itTodayPos->data;
ADD_TO_TODAY_VALUE(YdPosition);
ADD_TO_TODAY_VALUE(Position);
ADD_TO_TODAY_VALUE(LongFrozen);
ADD_TO_TODAY_VALUE(ShortFrozen);
ADD_TO_TODAY_VALUE(LongFrozenAmount);
ADD_TO_TODAY_VALUE(ShortFrozenAmount);
ADD_TO_TODAY_VALUE(OpenVolume);
ADD_TO_TODAY_VALUE(CloseVolume);
ADD_TO_TODAY_VALUE(OpenAmount);
ADD_TO_TODAY_VALUE(CloseAmount);
ADD_TO_TODAY_VALUE(PositionCost);
ADD_TO_TODAY_VALUE(PreMargin);
ADD_TO_TODAY_VALUE(UseMargin);
ADD_TO_TODAY_VALUE(FrozenMargin);
ADD_TO_TODAY_VALUE(FrozenCash);
ADD_TO_TODAY_VALUE(FrozenCommission);
ADD_TO_TODAY_VALUE(CashIn);
ADD_TO_TODAY_VALUE(Commission);
ADD_TO_TODAY_VALUE(CloseProfit);
ADD_TO_TODAY_VALUE(PositionProfit);
ADD_TO_TODAY_VALUE(OpenCost);
ADD_TO_TODAY_VALUE(ExchangeMargin);
ADD_TO_TODAY_VALUE(CombPosition);
ADD_TO_TODAY_VALUE(CombLongFrozen);
ADD_TO_TODAY_VALUE(CombShortFrozen);
ADD_TO_TODAY_VALUE(CloseProfitByDate);
ADD_TO_TODAY_VALUE(CloseProfitByTrade);
ADD_TO_TODAY_VALUE(TodayPosition);
}
}
const std::string deletePositionSql = "DELETE FROM CThostFtdcInvestorPositionField;";
m_sqlHandler.Delete(deletePositionSql);
for (auto& todayPos : todayPosVec)
{
todayPos.data.PositionDate =
(CLocalTraderApi::isSpecialExchange(todayPos.data.ExchangeID) ?
THOST_FTDC_PSD_History : THOST_FTDC_PSD_Today);
m_sqlHandler.Insert(todayPos.generateInsertSql());
}
accumulateTradingAccountFromPosition();
}
void CSettlementHandler::doWorkAfterSettlement(
const std::string& oldTradingDay, const std::string& newTradingDay)
{
CSqliteTransactionHandler transactionHandle(m_sqlHandler);
const std::string positiondetailUpdateAfterSettlementSql1
= "DELETE FROM CThostFtdcInvestorPositionDetailField WHERE Volume = 0;";
const std::string positiondetailUpdateAfterSettlementSql2
= "UPDATE CThostFtdcInvestorPositionDetailField \
SET TradingDay = '" + newTradingDay + "', LastSettlementPrice = SettlementPrice, \
CloseProfitByDate = 0, CloseProfitByTrade = 0, PositionProfitByDate = 0, \
CloseVolume = 0, CloseAmount = 0;";
m_sqlHandler.Delete(positiondetailUpdateAfterSettlementSql1);
m_sqlHandler.Update(positiondetailUpdateAfterSettlementSql2);
const std::string positionUpdateSqlAfterSettlementSql1 =
"DELETE FROM CThostFtdcInvestorPositionField WHERE Position = 0;";
const std::string positionUpdateSqlAfterSettlementSql2 =
"UPDATE CThostFtdcInvestorPositionField SET TradingDay = '" + newTradingDay
+ "', PreSettlementPrice = SettlementPrice, PreMargin = UseMargin, \
CloseProfit = 0, PositionProfit = 0, CloseProfitByDate = 0, CloseProfitByTrade = 0, \
LongFrozen = 0, ShortFrozen = 0, LongFrozenAmount = 0, ShortFrozenAmount = 0, \
FrozenMargin = 0, FrozenCash = 0, FrozenCommission = 0, YdPosition = Position, \
OpenVolume = 0, CloseVolume = 0, OpenAmount = 0, CloseAmount = 0, \
Commission = 0, TodayPosition = 0, CombLongFrozen = 0, CombShortFrozen = 0, CashIn = 0;";
m_sqlHandler.Delete(positionUpdateSqlAfterSettlementSql1);
m_sqlHandler.Update(positionUpdateSqlAfterSettlementSql2);
const std::string tradingAccountUpdateSqlAfterSettlement
= "UPDATE CThostFtdcTradingAccountField SET \
TradingDay = '" + newTradingDay + "', \
PreBalance = Balance, PreMargin = CurrMargin, Deposit = 0, Withdraw = 0;";
m_sqlHandler.Update(tradingAccountUpdateSqlAfterSettlement);
accumulateTradingAccountFromPosition();
CLocalTraderApi::tradingDay = newTradingDay;
for (auto& api : CLocalTraderApi::trade_api_set)
{
api->reloadAccountData();
}
}
struct MergedPositionData
{
int LongPositon;
double LongPositonCost;
int ShortPositon;
double ShortPositonCost;
double PositionProfit;
double UseMargin;
double SettlementPrice;
double PreSettlementPrice;
MergedPositionData(const CThostFtdcInvestorPositionField& pos = { 0 })
{
memset(this, 0, sizeof(*this));
updateByPosition(pos);
}
void updateByPosition(const CThostFtdcInvestorPositionField& pos)
{
if (pos.PosiDirection == THOST_FTDC_PD_Long)
{
LongPositon += pos.Position;
LongPositonCost += pos.PositionCost;
}
else
{
ShortPositon += pos.Position;
ShortPositonCost += pos.PositionCost;
}
PositionProfit += pos.PositionProfit;
UseMargin += pos.UseMargin;
SettlementPrice = pos.SettlementPrice;
PreSettlementPrice = pos.PreSettlementPrice;
}
};
void CSettlementHandler::doGenerateUserSettlement(
const CThostFtdcTradingAccountFieldWrapper& tradingAccountFieldWrapper,
const std::string& TradingDay)
{
const auto& data = tradingAccountFieldWrapper.data;
const std::string brokerID = data.BrokerID;
const std::string userID = data.AccountID;
SettlementDataWrapper settlementDataWrapper;
SettlementData& settlementData = settlementDataWrapper.data;
strncpy(settlementData.BrokerID, brokerID.c_str(), sizeof(settlementData.BrokerID));
strncpy(settlementData.InvestorID, userID.c_str(), sizeof(settlementData.InvestorID));
strncpy(settlementData.TradingDay, TradingDay.c_str(), sizeof(settlementData.TradingDay));
std::ostringstream ostrstr;
char ch_single_line[512] = { 0 };
auto buildSettlementHead = [&]() {
sprintf(ch_single_line, format_settlement_header1.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header2.c_str(), TradingDay.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header3.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header4.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header5.c_str(), userID.c_str(), userID.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header6.c_str(), TradingDay.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header7.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header8.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header9.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_header10.c_str());
ostrstr << ch_single_line << "\r\n";
};
auto buildSettlementTradingAccount = [&]() {
double positiveCashIn(0);
CSqliteHandler::SQL_VALUES tradeSqlValues;
const std::string selectTradeSql =
"SELECT SUM(CashIn) AS positiveCashIn FROM 'CThostFtdcTradeField' where BrokerID='"
+ brokerID + "' and InvestorID='" + userID
+ "' and TradingDay = '" + TradingDay
+ "' and CashIn>0;";
m_sqlHandler.SelectData(selectTradeSql, tradeSqlValues);
for (const auto& rowValue : tradeSqlValues)
{
try
{
positiveCashIn = std::stod(rowValue.at("positiveCashIn"));
}
catch (...)
{
positiveCashIn = 0;
}
break;
}
double negativeCashIn = data.CashIn - positiveCashIn;
sprintf(ch_single_line, format_settlement_account_summary1.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary2.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary3.c_str(), data.PreBalance, 0.0);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary4.c_str(), data.Deposit - data.Withdraw, data.Balance); ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary5.c_str(), data.CloseProfit, 0.0);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary6.c_str(), data.PositionProfit, data.Balance);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary7.c_str(), 0.0, 0.0);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary8.c_str(), data.Commission, data.CurrMargin);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary9.c_str(), 0.0, 0.0);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary10.c_str(), 0.0, 0.0);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary11.c_str(), 0.0, 0.0);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary12.c_str(), 0.0, data.Balance);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary13.c_str(), 0.0, data.Available);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary14.c_str(), positiveCashIn, 100 * (LEZ(data.Balance) ? 1.0 : data.CurrMargin) / data.Balance);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary15.c_str(), negativeCashIn, (LTZ(data.Available) ? (0 - data.Available) : 0));
ostrstr << ch_single_line << "\r\n";
std::ostringstream runningModeStr;
runningModeStr << CLocalTraderApi::m_runningMode;
sprintf(ch_single_line, format_settlement_account_summary16.c_str(), runningModeStr.str().c_str(), CLeeDateTime::now().Format().c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_account_summary17.c_str());
ostrstr << ch_single_line << "\r\n";
};
auto buildSettlementTrade = [&]() {
CSqliteHandler::SQL_VALUES tradeSqlValues;
const std::string selectTradeSql =
"SELECT * FROM 'CThostFtdcTradeField' where BrokerID='"
+ brokerID + "' and InvestorID='" + userID
+ "' and TradingDay = '" + TradingDay
+"' ORDER BY TradeID ASC ;";
m_sqlHandler.SelectData(selectTradeSql, tradeSqlValues);
if (tradeSqlValues.empty()) {
return;
}
sprintf(ch_single_line, format_settlement_trade_head1.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_head2.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_head3.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_head4.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_head5.c_str());
ostrstr << ch_single_line << "\r\n";
int total_Lots = 0; double total_Turnover = 0.0; double total_Fee = 0.0; double total_CloseProfit = 0.0; double total_CashIn = 0.0; for (const auto& tradeValue : tradeSqlValues)
{
CThostFtdcTradeFieldWrapper tradeWrapper(tradeValue);
const auto& trade = tradeWrapper.data;
auto itInstr = CLocalTraderApi::m_instrData.find(trade.InstrumentID);
if (itInstr == CLocalTraderApi::m_instrData.end())
{
continue;
}
const CThostFtdcInstrumentField& ContractInfo = itInstr->second;
auto itProduct = CLocalTraderApi::m_products.find(ContractInfo.ProductID);
if (itProduct == CLocalTraderApi::m_products.end())
{
continue;
}
int thisLots = trade.Volume; total_Lots += thisLots;
double thisTurnover = trade.Price * thisLots * ContractInfo.VolumeMultiple; total_Turnover += thisTurnover;
total_CloseProfit += tradeWrapper.CloseProfit; total_Fee += tradeWrapper.Commission; total_CashIn += tradeWrapper.CashIn; sprintf(ch_single_line, format_settlement_trade_single_record1.c_str(),
TradingDay.c_str(),
get_exchange_name(ContractInfo.ExchangeID).c_str(),
itProduct->second.ProductName,
trade.InstrumentID,
get_direction_name(trade.Direction).c_str(),
trade.Price,
thisLots,
thisTurnover,
get_open_close_name(trade.OffsetFlag).c_str(),
tradeWrapper.Commission,
tradeWrapper.CloseProfit,
tradeWrapper.CashIn,
trade.TradeID);
ostrstr << ch_single_line << "\r\n";
}
sprintf(ch_single_line, format_settlement_trade_end1.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_end2.c_str(), (int)tradeSqlValues.size(), total_Lots, total_Turnover, total_Fee, total_CloseProfit, total_CashIn);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_end3.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_end4.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_end5.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_end6.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_end7.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_trade_end8.c_str());
ostrstr << ch_single_line << "\r\n";
};
auto buildSettlementCloseDetail = [&]() {
CSqliteHandler::SQL_VALUES closeDetailSqlValues;
const std::string selectCloseDetailSql =
"SELECT * FROM 'CloseDetail' where BrokerID='"
+ brokerID + "' and InvestorID='" + userID
+ "' and CloseDate = '" + TradingDay
+ "';";
m_sqlHandler.SelectData(selectCloseDetailSql, closeDetailSqlValues);
if (closeDetailSqlValues.empty()) {
return;
}
sprintf(ch_single_line, format_settlement_position_closed_head1.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_head2.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_head3.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_head4.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_head5.c_str());
ostrstr << ch_single_line << "\r\n";
int total_position_closed_lots = 0; double total_position_closed_close_profit = 0.0; double total_position_closed_cashIn = 0.0; for (const auto& closeDetailValue : closeDetailSqlValues)
{
CloseDetailWrapper closeDetailWrapper(closeDetailValue);
const auto& closeDetail = closeDetailWrapper.data;
auto itInstr = CLocalTraderApi::m_instrData.find(closeDetail.InstrumentID);
if (itInstr == CLocalTraderApi::m_instrData.end())
{
continue;
}
const CThostFtdcInstrumentField& ContractInfo = itInstr->second;
auto itProduct = CLocalTraderApi::m_products.find(ContractInfo.ProductID);
if (itProduct == CLocalTraderApi::m_products.end())
{
continue;
}
total_position_closed_lots += closeDetail.CloseVolume;
total_position_closed_close_profit += closeDetail.CloseProfit;
total_position_closed_cashIn += closeDetail.CashIn;
sprintf(ch_single_line, format_settlement_position_closed_single_record1.c_str(),
closeDetail.CloseDate,
get_exchange_name(ContractInfo.ExchangeID).c_str(),
itProduct->second.ProductName,
closeDetail.InstrumentID,
closeDetail.OpenDate,
get_direction_name(closeDetail.Direction).c_str(),
closeDetail.CloseVolume,
closeDetail.OpenPrice,
closeDetail.PreSettlementPrice,
closeDetail.ClosePrice,
closeDetail.CloseProfit,
closeDetail.CashIn);
ostrstr << ch_single_line << "\r\n";
}
sprintf(ch_single_line, format_settlement_position_closed_end1.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_end2.c_str(), (int)closeDetailSqlValues.size(), total_position_closed_lots, total_position_closed_close_profit, total_position_closed_cashIn);
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_end3.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_end4.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_end5.c_str());
ostrstr << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_closed_end6.c_str());
ostrstr << ch_single_line << "\r\n";
};
auto buildSettlementPositionDetail = [&]() {
CSqliteHandler::SQL_VALUES posDetailSqlValues;
const std::string selectPosDetailSql =
"SELECT * FROM 'CThostFtdcInvestorPositionDetailField' where BrokerID='"
+ brokerID + "' and InvestorID='"
+ userID + "' and Volume != 0;";
m_sqlHandler.SelectData(selectPosDetailSql, posDetailSqlValues);
if (posDetailSqlValues.empty()) {
return;
}
std::ostringstream ostrstr_position_detail;
sprintf(ch_single_line, format_settlement_position_detail_head1.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_head2.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_head3.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_head4.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_head5.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
int total_Position = 0; double total_FloatProfit = 0.0; double total_PositionProfit = 0.0; double total_Margin = 0.0; for (const auto& posDetailValue : posDetailSqlValues)
{
CThostFtdcInvestorPositionDetailFieldWrapper posDetailWrapper(posDetailValue);
const auto& posDetail = posDetailWrapper.data;
auto itInstr = CLocalTraderApi::m_instrData.find(posDetail.InstrumentID);
if (itInstr == CLocalTraderApi::m_instrData.end())
{
continue;
}
const CThostFtdcInstrumentField& ContractInfo = itInstr->second;
auto itProduct = CLocalTraderApi::m_products.find(ContractInfo.ProductID);
if (itProduct == CLocalTraderApi::m_products.end())
{
continue;
}
total_Position += posDetail.Volume; total_FloatProfit += posDetail.PositionProfitByTrade; total_PositionProfit += posDetail.PositionProfitByDate; total_Margin += posDetail.Margin;
sprintf(ch_single_line, format_settlement_position_detail_single_record1.c_str(),
get_exchange_name(ContractInfo.ExchangeID).c_str(),
itProduct->second.ProductName,
posDetail.InstrumentID,
posDetail.OpenDate,
get_direction_name(posDetail.Direction).c_str(),
posDetail.Volume,
posDetail.OpenPrice,
posDetail.LastSettlementPrice,
posDetail.SettlementPrice,
posDetail.PositionProfitByTrade,
posDetail.PositionProfitByDate,
posDetail.Margin);
ostrstr_position_detail << ch_single_line << "\r\n";
}
sprintf(ch_single_line, format_settlement_position_detail_end1.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_end2.c_str(), (int)posDetailSqlValues.size(), total_Position, total_FloatProfit, total_PositionProfit, total_Margin);
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_end3.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_end4.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_end5.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_end6.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_detail_end7.c_str());
ostrstr_position_detail << ch_single_line << "\r\n";
ostrstr << ostrstr_position_detail.str();
};
auto buildSettlementPosition = [&]() {
CSqliteHandler::SQL_VALUES posSqlValues;
const std::string selectPosSql =
"SELECT * FROM 'CThostFtdcInvestorPositionField' where BrokerID='"
+ brokerID + "' and InvestorID='"
+ userID + "' and Position != 0;";
m_sqlHandler.SelectData(selectPosSql, posSqlValues);
if (posSqlValues.empty()) {
return;
}
std::ostringstream ostrstr_position;
sprintf(ch_single_line, format_settlement_position_head1.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_head2.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_head3.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_head4.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_head5.c_str());
ostrstr_position << ch_single_line << "\r\n";
int total_LongPositon = 0; int total_ShortPositon = 0; double total_PositionProfit = 0.0; double total_Margin = 0.0;
std::map<std::string, MergedPositionData> mergedPositions;
for (const auto& posValue : posSqlValues)
{
CThostFtdcInvestorPositionFieldWrapper posWrapper(posValue);
const auto& pos = posWrapper.data;
auto itPosInMergedPositions = mergedPositions.find(pos.InstrumentID);
if (itPosInMergedPositions == mergedPositions.end()) {
MergedPositionData temp(pos);
mergedPositions.emplace(pos.InstrumentID, temp);
}
else
{
itPosInMergedPositions->second.updateByPosition(pos);
}
}
for (const auto& posInMergedPositionPair : mergedPositions)
{
const auto& posInMergedPosition = posInMergedPositionPair.second;
auto itInstr = CLocalTraderApi::m_instrData.find(posInMergedPositionPair.first);
if (itInstr == CLocalTraderApi::m_instrData.end())
{
continue;
}
const CThostFtdcInstrumentField& ContractInfo = itInstr->second;
auto itProduct = CLocalTraderApi::m_products.find(ContractInfo.ProductID);
if (itProduct == CLocalTraderApi::m_products.end())
{
continue;
}
total_LongPositon += posInMergedPosition.LongPositon; total_ShortPositon += posInMergedPosition.ShortPositon; total_PositionProfit += posInMergedPosition.PositionProfit; total_Margin += posInMergedPosition.UseMargin;
const double LongAvgPrice = (posInMergedPosition.LongPositon == 0 ?
0.0 :
(posInMergedPosition.LongPositonCost / (1.0 * posInMergedPosition.LongPositon * ContractInfo.VolumeMultiple)));
const double ShortAvgPrice = (posInMergedPosition.ShortPositon == 0 ?
0.0 :
(posInMergedPosition.ShortPositonCost / (1.0 * posInMergedPosition.ShortPositon * ContractInfo.VolumeMultiple)));
sprintf(ch_single_line, format_settlement_position_single_record1.c_str(),
itProduct->second.ProductName,
posInMergedPositionPair.first.c_str(),
posInMergedPosition.LongPositon,
LongAvgPrice,
posInMergedPosition.ShortPositon,
ShortAvgPrice,
posInMergedPosition.PreSettlementPrice,
posInMergedPosition.SettlementPrice,
posInMergedPosition.PositionProfit,
posInMergedPosition.UseMargin);
ostrstr_position << ch_single_line << "\r\n";
}
sprintf(ch_single_line, format_settlement_position_end1.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_end2.c_str(), (int)mergedPositions.size(), total_LongPositon, total_ShortPositon, total_PositionProfit, total_Margin);
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_end3.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_end4.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_end5.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_end6.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_end7.c_str());
ostrstr_position << ch_single_line << "\r\n";
sprintf(ch_single_line, format_settlement_position_end8.c_str());
ostrstr_position << ch_single_line << "\r\n";
ostrstr << ostrstr_position.str();
};
buildSettlementHead(); buildSettlementTradingAccount(); buildSettlementTrade(); buildSettlementCloseDetail(); buildSettlementPositionDetail(); buildSettlementPosition();
const std::string str_to_encode = ostrstr.str();
settlementData.SettlementContent =
base64_encode(reinterpret_cast<const unsigned char*>(str_to_encode.c_str()),
static_cast<unsigned int>(str_to_encode.size()));
m_sqlHandler.Insert(settlementDataWrapper.generateInsertSql());
}
}