用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

575 lines
20 KiB

10 months ago
/*****************************************************************************
* Copyright [2019]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*****************************************************************************/
#include <Common/util.h>
#include <Common/datastruct.h>
#include <string>
using namespace std;
namespace StarQuant {
// unique order id on server side defined in ordermanager.cpp,
// Every broker has its own id;
int64_t m_serverOrderId = 0;
// mutex for increasing order id
std::mutex oid_mtx;
// mutex for changing order status
std::mutex orderStatus_mtx;
MSG_TYPE MsgType(const string& msg) {
string header;
stringstream ss(msg);
getline(ss, header, SERIALIZATION_SEPARATOR);
getline(ss, header, SERIALIZATION_SEPARATOR);
getline(ss, header, SERIALIZATION_SEPARATOR);
MSG_TYPE msgtype_ = MSG_TYPE(atoi(header.c_str()));
return msgtype_;
}
string MsgFrame::serialize() {
string tmp = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_);
if (dataPtr != nullptr) {
tmp = tmp + SERIALIZATION_SEPARATOR + dataPtr->serialize();
}
return tmp;
}
void MsgFrame::deserialize(const string& msgin) {
string des;
string src;
string stype;
string datas;
stringstream ss(msgin);
getline(ss, des, SERIALIZATION_SEPARATOR);
getline(ss, src, SERIALIZATION_SEPARATOR);
getline(ss, stype, SERIALIZATION_SEPARATOR);
getline(ss, datas);
MSG_TYPE mtype = MSG_TYPE(stoi(stype));
destination_ = des;
source_ = src;
msgtype_ = mtype;
if (!datas.empty())
dataPtr->deserialize(datas);
}
string accAddress(const string& msg) {
string acc;
stringstream ss(msg);
getline(ss, acc, DESTINATION_SEPARATOR);
getline(ss, acc, DESTINATION_SEPARATOR);
getline(ss, acc, DESTINATION_SEPARATOR);
return acc;
}
string TickMsg::serialize() {
string ba; // bid ask price and size
for (int32_t i = 0; i < data_.depth_; i++) {
ba = ba
+ SERIALIZATION_SEPARATOR + to_string(data_.bidPrice_[i])
+ SERIALIZATION_SEPARATOR + to_string(data_.bidSize_[i])
+ SERIALIZATION_SEPARATOR + to_string(data_.askPrice_[i])
+ SERIALIZATION_SEPARATOR + to_string(data_.askSize_[i]);
}
string s;
s = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + data_.fullSymbol_
+ SERIALIZATION_SEPARATOR + data_.time_
+ SERIALIZATION_SEPARATOR + to_string(data_.price_)
+ SERIALIZATION_SEPARATOR + to_string(data_.size_)
+ ba
+ SERIALIZATION_SEPARATOR + to_string(data_.openInterest_)
+ SERIALIZATION_SEPARATOR + to_string(data_.open_)
+ SERIALIZATION_SEPARATOR + to_string(data_.high_)
+ SERIALIZATION_SEPARATOR + to_string(data_.low_)
+ SERIALIZATION_SEPARATOR + to_string(data_.preClose_)
+ SERIALIZATION_SEPARATOR + to_string(data_.upperLimitPrice_)
+ SERIALIZATION_SEPARATOR + to_string(data_.lowerLimitPrice_);
return s;
}
string SecurityMsg::serialize() {
string s;
s = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + data_.symbol_
+ SERIALIZATION_SEPARATOR + data_.exchange_
+ SERIALIZATION_SEPARATOR + data_.localName_
+ SERIALIZATION_SEPARATOR + data_.securityType_
+ SERIALIZATION_SEPARATOR + to_string(data_.multiplier_)
+ SERIALIZATION_SEPARATOR + to_string(data_.ticksize_)
+ SERIALIZATION_SEPARATOR + data_.postype_
+ SERIALIZATION_SEPARATOR + to_string(data_.longMarginRatio_)
+ SERIALIZATION_SEPARATOR + to_string(data_.shortMarginRatio_)
+ SERIALIZATION_SEPARATOR + data_.underlyingSymbol_
+ SERIALIZATION_SEPARATOR + data_.optionType_
+ SERIALIZATION_SEPARATOR + to_string(data_.strikePrice_)
+ SERIALIZATION_SEPARATOR + data_.expiryDate_;
return s;
}
string AccMsg::serialize() {
string s;
s = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + data_.accountID_
+ SERIALIZATION_SEPARATOR + to_string(data_.previousDayEquityWithLoanValue_)
+ SERIALIZATION_SEPARATOR + to_string(data_.netLiquidation_)
+ SERIALIZATION_SEPARATOR + to_string(data_.availableFunds_)
+ SERIALIZATION_SEPARATOR + to_string(data_.commission_)
+ SERIALIZATION_SEPARATOR + to_string(data_.fullMaintainanceMargin_)
+ SERIALIZATION_SEPARATOR + to_string(data_.realizedPnL_)
+ SERIALIZATION_SEPARATOR + to_string(data_.unrealizedPnL_)
+ SERIALIZATION_SEPARATOR + to_string(data_.balance_)
+ SERIALIZATION_SEPARATOR + to_string(data_.frozen_)
+ SERIALIZATION_SEPARATOR + ymdhmsf();
return s;
}
string FillMsg::serialize() {
string str = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.serverOrderID_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.clientOrderID_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.clientID_)
+ SERIALIZATION_SEPARATOR + data_.localNo_
+ SERIALIZATION_SEPARATOR + data_.orderNo_
+ SERIALIZATION_SEPARATOR + data_.tradeNo_
+ SERIALIZATION_SEPARATOR + data_.tradeTime_
+ SERIALIZATION_SEPARATOR + data_.fullSymbol_
+ SERIALIZATION_SEPARATOR + std::to_string(data_.tradePrice_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.tradeSize_)
+ SERIALIZATION_SEPARATOR + std::to_string(static_cast<int32_t>(data_.fillFlag_))
+ SERIALIZATION_SEPARATOR + std::to_string(data_.commission_)
+ SERIALIZATION_SEPARATOR + data_.account_
+ SERIALIZATION_SEPARATOR + data_.api_
+ SERIALIZATION_SEPARATOR + ymdhms();
return str;
}
bool isActiveOrder(const Order& o) {
if (o.orderStatus_ == OrderStatus::OS_Filled)
return false;
if (o.orderStatus_ == OrderStatus::OS_Error)
return false;
if (o.orderStatus_ == OrderStatus::OS_Canceled)
return false;
return true;
}
bool isActiveOS(const OrderStatus& os) {
if (os == OrderStatus::OS_Filled)
return false;
if (os == OrderStatus::OS_Error)
return false;
if (os == OrderStatus::OS_Canceled)
return false;
return true;
}
void OrderMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 8)
throw std::out_of_range("OutofRange in Order deserialize");
destination_ = v[0];
source_ = v[1];
data_.api_ = v[3];
data_.account_ = v[4];
data_.clientID_ = stoi(v[5]);
data_.clientOrderID_ = stol(v[6]);
data_.tag_ = v[7];
// data_.clientID_ = stoi(v[1]);
// data_.clientOrderID_ = stol(v[4]);
// data_.orderType_ = static_cast<OrderType>(stoi(v[5]));
// data_.fullSymbol_ = v[6];
// data_.orderSize_ = stoi(v[7]);
// if (data_.orderType_ == OrderType::OT_Limit){
// data_.limitPrice_ = stof(v[8]);
// }else if (data_.orderType_ == OrderType::OT_StopLimit){
// data_.stopPrice_ = stof(v[8]);
// }
// data_.orderFlag_ = static_cast<OrderFlag>(stoi(v[9]));
// data_.tag_ = v[10];
}
std::shared_ptr<Order> OrderMsg::toPOrder() {
std::shared_ptr<Order> o = make_shared<Order>();
o->api_ = data_.api_;
o->account_ = data_.account_;
o->clientID_ = data_.clientID_;
o->clientOrderID_ = data_.clientOrderID_;
o->tag_ = data_.tag_;
o->orderType_ = data_.orderType_;
o->fullSymbol_ = data_.fullSymbol_;
o->price_ = data_.price_;
o->quantity_ = data_.quantity_;
o->tradedvol_ = data_.tradedvol_;
o->flag_ = data_.flag_;
o->serverOrderID_ = data_.serverOrderID_;
o->brokerOrderID_ = data_.brokerOrderID_;
o->orderNo_ = data_.orderNo_;
o->localNo_ = data_.localNo_;
o->createTime_ = data_.createTime_;
o->updateTime_ = data_.updateTime_;
o->orderStatus_ = data_.orderStatus_;
return o;
}
void PaperOrderMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 14)
throw std::out_of_range("OutofRange in PaperOrder deserialize.");
destination_ = v[0];
source_ = v[1];
data_.api_ = v[3];
data_.account_ = v[4];
data_.clientID_ = stoi(v[5]);
data_.clientOrderID_ = stol(v[6]);
data_.tag_ = v[7];
data_.orderType_ = static_cast<OrderType>(stoi(v[8]));
data_.fullSymbol_ = v[9];
data_.orderFlag_ = static_cast<OrderFlag>(stoi(v[10]));
data_.orderSize_ = stoi(v[11]);
data_.limitPrice_ = stof(v[12]);
data_.stopPrice_ = stof(v[13]);
}
std::shared_ptr<Order> PaperOrderMsg::toPOrder() {
auto o = make_shared<PaperOrder>();
o->api_ = data_.api_;
o->account_ = data_.account_;
o->clientID_ = data_.clientID_;
o->clientOrderID_ = data_.clientOrderID_;
o->tag_ = data_.tag_;
o->fullSymbol_ = data_.fullSymbol_;
o->price_ = data_.price_;
o->quantity_ = data_.quantity_;
o->tradedvol_ = data_.tradedvol_;
o->flag_ = data_.flag_;
o->serverOrderID_ = data_.serverOrderID_;
o->brokerOrderID_ = data_.brokerOrderID_;
o->orderNo_ = data_.orderNo_;
o->localNo_ = data_.localNo_;
o->createTime_ = data_.createTime_;
o->updateTime_ = data_.updateTime_;
o->orderStatus_ = data_.orderStatus_;
o->orderType_ = data_.orderType_;
o->orderSize_ = data_.orderSize_;
o->limitPrice_ = data_.limitPrice_;
o->stopPrice_ = data_.stopPrice_;
o->orderFlag_ = data_.orderFlag_;
return o;
}
void CtpOrderMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 27)
throw std::out_of_range("OutofRange in CtpOrder deserialize.");
destination_ = v[0];
source_ = v[1];
data_.api_ = v[3];
data_.account_ = v[4];
data_.clientID_ = stoi(v[5]);
data_.clientOrderID_ = stol(v[6]);
data_.tag_ = v[7];
data_.orderType_ = OrderType(stoi(v[7]));
data_.orderField_ = {};
strcpy(data_.orderField_.InstrumentID, v[8].c_str());
data_.orderField_.OrderPriceType = v[9][0];
data_.orderField_.Direction = v[10][0];
strcpy(data_.orderField_.CombOffsetFlag, v[11].c_str());
strcpy(data_.orderField_.CombHedgeFlag, v[12].c_str());
data_.orderField_.LimitPrice = stof(v[13]);
data_.orderField_.VolumeTotalOriginal = stoi(v[14]);
data_.orderField_.TimeCondition = v[15][0];
strcpy(data_.orderField_.GTDDate, v[16].c_str());
data_.orderField_.VolumeCondition = v[17][0];
data_.orderField_.MinVolume = stoi(v[18]);
data_.orderField_.ContingentCondition = v[19][0];
data_.orderField_.StopPrice = stof(v[20]);
data_.orderField_.ForceCloseReason = v[21][0];
data_.orderField_.IsAutoSuspend = stoi(v[22]);
data_.orderField_.UserForceClose = stoi(v[23]);
data_.orderField_.IsSwapOrder = stoi(v[24]);
strcpy(data_.orderField_.BusinessUnit, v[25].c_str());
strcpy(data_.orderField_.CurrencyID, v[26].c_str());
}
std::shared_ptr<Order> CtpOrderMsg::toPOrder() {
std::shared_ptr<CtpOrder> o = make_shared<CtpOrder>();
o->api_ = data_.api_;
o->account_ = data_.account_;
o->clientID_ = data_.clientID_;
o->clientOrderID_ = data_.clientOrderID_;
o->tag_ = data_.tag_;
o->orderType_ = data_.orderType_;
o->fullSymbol_ = data_.fullSymbol_;
o->price_ = data_.price_;
o->quantity_ = data_.quantity_;
o->tradedvol_ = data_.tradedvol_;
o->flag_ = data_.flag_;
o->serverOrderID_ = data_.serverOrderID_;
o->brokerOrderID_ = data_.brokerOrderID_;
o->orderNo_ = data_.orderNo_;
o->localNo_ = data_.localNo_;
o->createTime_ = data_.createTime_;
o->updateTime_ = data_.updateTime_;
o->orderStatus_ = data_.orderStatus_;
memcpy(&o->orderField_, &data_.orderField_, sizeof(CThostFtdcInputOrderField));
// return static_pointer_cast<Order>(o);
return o;
}
void CtpParkedOrderMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 27)
throw std::out_of_range("OutofRange in CtpParkOrder deserialize.");
destination_ = v[0];
source_ = v[1];
data_.api_ = v[3];
data_.account_ = v[4];
data_.clientID_ = stoi(v[5]);
data_.clientOrderID_ = stol(v[6]);
data_.tag_ = v[7];
data_.parkedOrderField_ = {};
strcpy(data_.parkedOrderField_.InstrumentID, v[8].c_str());
data_.parkedOrderField_.OrderPriceType = v[9][0];
data_.parkedOrderField_.Direction = v[10][0];
strcpy(data_.parkedOrderField_.CombOffsetFlag, v[11].c_str());
strcpy(data_.parkedOrderField_.CombHedgeFlag, v[12].c_str());
data_.parkedOrderField_.LimitPrice = stof(v[13]);
data_.parkedOrderField_.VolumeTotalOriginal = stoi(v[14]);
data_.parkedOrderField_.TimeCondition = v[15][0];
strcpy(data_.parkedOrderField_.GTDDate, v[16].c_str());
data_.parkedOrderField_.VolumeCondition = v[17][0];
data_.parkedOrderField_.MinVolume = stoi(v[18]);
data_.parkedOrderField_.ContingentCondition = v[19][0];
data_.parkedOrderField_.StopPrice = stof(v[20]);
data_.parkedOrderField_.ForceCloseReason = v[21][0];
data_.parkedOrderField_.IsAutoSuspend = stoi(v[22]);
data_.parkedOrderField_.UserForceClose = stoi(v[23]);
data_.parkedOrderField_.IsSwapOrder = stoi(v[24]);
strcpy(data_.parkedOrderField_.BusinessUnit, v[25].c_str());
strcpy(data_.parkedOrderField_.CurrencyID, v[26].c_str());
}
std::shared_ptr<Order> CtpParkedOrderMsg::toPOrder() {
auto o = make_shared<CtpParkedOrder>();
o->api_ = data_.api_;
o->account_ = data_.account_;
o->clientID_ = data_.clientID_;
o->clientOrderID_ = data_.clientOrderID_;
o->tag_ = data_.tag_;
o->fullSymbol_ = data_.fullSymbol_;
o->price_ = data_.price_;
o->quantity_ = data_.quantity_;
o->tradedvol_ = data_.tradedvol_;
o->flag_ = data_.flag_;
o->serverOrderID_ = data_.serverOrderID_;
o->brokerOrderID_ = data_.brokerOrderID_;
o->orderNo_ = data_.orderNo_;
o->localNo_ = data_.localNo_;
o->createTime_ = data_.createTime_;
o->updateTime_ = data_.updateTime_;
o->orderStatus_ = data_.orderStatus_;
memcpy(&o->parkedOrderField_, &data_.parkedOrderField_, sizeof(CThostFtdcParkedOrderField));
//return static_pointer_cast<Order>(o);
return o;
}
void OrderStatusMsg::set(std::shared_ptr<Order> po) {
// data_ = *po;
data_.api_ = po->api_;
data_.account_ = po->account_;
data_.clientID_ = po->clientID_;
data_.clientOrderID_ = po->clientOrderID_;
data_.tag_ = po->tag_;
data_.orderType_ = po->orderType_;
data_.fullSymbol_ = po->fullSymbol_;
data_.price_ = po->price_;
data_.quantity_ = po->quantity_;
data_.tradedvol_ = po->tradedvol_;
data_.flag_ = po->flag_;
data_.serverOrderID_ = po->serverOrderID_;
data_.brokerOrderID_ = po->brokerOrderID_;
data_.orderNo_ = po->orderNo_;
data_.localNo_ = po->localNo_;
data_.createTime_ = po->createTime_;
data_.updateTime_ = po->updateTime_;
data_.orderStatus_ = po->orderStatus_;
}
string OrderStatusMsg::serialize() {
string str = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + data_.api_
+ SERIALIZATION_SEPARATOR + data_.account_
+ SERIALIZATION_SEPARATOR + std::to_string(data_.clientID_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.clientOrderID_)
+ SERIALIZATION_SEPARATOR + data_.tag_
+ SERIALIZATION_SEPARATOR + data_.fullSymbol_
+ SERIALIZATION_SEPARATOR + std::to_string(data_.price_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.quantity_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.tradedvol_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.flag_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.serverOrderID_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.brokerOrderID_)
+ SERIALIZATION_SEPARATOR + data_.orderNo_
+ SERIALIZATION_SEPARATOR + data_.localNo_
+ SERIALIZATION_SEPARATOR + data_.createTime_
+ SERIALIZATION_SEPARATOR + data_.updateTime_
+ SERIALIZATION_SEPARATOR + std::to_string(data_.orderStatus_);
return str;
}
string PosMsg::serialize() {
string str = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + data_.key_
+ SERIALIZATION_SEPARATOR + data_.account_
+ SERIALIZATION_SEPARATOR + data_.api_
+ SERIALIZATION_SEPARATOR + data_.fullSymbol_
+ SERIALIZATION_SEPARATOR + data_.type_
+ SERIALIZATION_SEPARATOR + std::to_string(data_.avgPrice_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.size_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.preSize_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.freezedSize_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.closedpl_)
+ SERIALIZATION_SEPARATOR + std::to_string(data_.openpl_)
+ SERIALIZATION_SEPARATOR + ymdhmsf();
return str;
}
void PosMsg::set(std::shared_ptr<Position> pp) {
// data_ = *pp;
data_.key_ = pp->key_;
data_.account_ = pp->account_;
data_.api_ = pp->api_;
data_.fullSymbol_ = pp->fullSymbol_;
data_.avgPrice_ = pp->avgPrice_;
data_.size_ = pp->size_;
data_.preSize_ = pp->preSize_;
data_.freezedSize_ = pp->freezedSize_;
data_.openpl_ = pp->openpl_;
data_.closedpl_ = pp->closedpl_;
data_.type_ = pp->type_;
data_.posNo_ = pp->posNo_;
}
void OrderActionMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 6)
throw std::out_of_range("OutofRange in OrderAction deserialize.");
destination_ = v[0];
source_ = v[1];
data_.clientID_ = stoi(v[3]);
data_.clientOrderID_ = stol(v[4]);
data_.serverOrderID_ = stol(v[5]);
}
void SubscribeMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 5)
throw std::out_of_range("OutofRange in Subscribe deserialize.");
destination_ = v[0];
source_ = v[1];
symtype_ = SymbolType(stoi(v[3]));
for (int32_t i = 4; i < v.size(); i++)
data_.push_back(v[i]);
}
void UnSubscribeMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 5)
throw std::out_of_range("OutofRange in Unsubscribe deserialize.");
destination_ = v[0];
source_ = v[1];
symtype_ = SymbolType(stoi(v[3]));
for (int32_t i = 4; i < v.size(); i++)
data_.push_back(v[i]);
}
void QryContractMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 5)
throw std::out_of_range("OutofRange in qrycontract deserialize.");
destination_ = v[0];
source_ = v[1];
symtype_ = SymbolType(stoi(v[3]));
data_ = v[4];
}
void CancelAllMsg::deserialize(const string& msgin) {
vector<string> v = stringsplit(msgin, SERIALIZATION_SEPARATOR);
if (v.size() < 5)
throw std::out_of_range("OutofRange in cancelall deserialize.");
destination_ = v[0];
source_ = v[1];
symtype_ = SymbolType(stoi(v[3]));
data_ = v[4];
}
string ErrorMsg::serialize() {
string str = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + data_
+ SERIALIZATION_SEPARATOR + ymdhms();
return str;
}
string InfoMsg::serialize() {
string str = destination_
+ SERIALIZATION_SEPARATOR + source_
+ SERIALIZATION_SEPARATOR + to_string(msgtype_)
+ SERIALIZATION_SEPARATOR + data_
+ SERIALIZATION_SEPARATOR + ymdhms();
return str;
}
} // namespace StarQuant