Files
spark/src/lib/domain/DomainSecurityUtils.cpp
T
John Colvin 6f086532ac cleanup: Convert co2::TradeMessage in DomainSecurityUtils
Instead of domain::TradeRecord constructor. The domain types should have
minimal dependency on protos.
2025-01-28 19:59:09 +00:00

293 lines
9.7 KiB
C++

#include "DomainSecurityUtils.h"
#include "FutureSecurity.h"
#include "OptionSecurity.h"
#include "SpreadSecurity.h"
#include "lib/api/domain/Venue.pb.h"
#include "lib/domain/TradeRecord.h"
#include "lib/domain_model/Security.pb.h"
#include "lib/md/IntPrice.h"
#include "lib/md/PriceSize.h"
#include "lib/md/protos/co2.pb.h"
#include "lib/utils/bts_assert.h"
namespace bts::domain {
#define DOMAIN_VENUE(x) bts::api::domain::VENUE_##x
#define DOMAIN_SEC_TYPE(x) bts::api::domain::SECURITY_TYPE_##x
api::domain::Venue DomainSecurityUtils::convert(bts::api::Venue venue) {
switch (venue) {
case bts::api::Venue::VENUE_GLBX:
return DOMAIN_VENUE(GLBX);
case bts::api::Venue::VENUE_DERIBIT:
return DOMAIN_VENUE(DERIBIT);
case bts::api::Venue::VENUE_CBOE:
return DOMAIN_VENUE(CBOE);
case bts::api::Venue::VENUE_TAIFEX:
return DOMAIN_VENUE(TAIFEX);
case bts::api::Venue::VENUE_BTS:
return DOMAIN_VENUE(BTS);
case bts::api::Venue::VENUE_SIM:
return DOMAIN_VENUE(SIM);
case bts::api::Venue::VENUE_BINANCE:
return DOMAIN_VENUE(BINANCE);
case bts::api::Venue::VENUE_BINANCE_COIN_FUTURES:
return DOMAIN_VENUE(BINANCE_COIN_FUTURES);
case bts::api::Venue::VENUE_BINANCE_US:
return DOMAIN_VENUE(BINANCE_US);
case bts::api::VENUE_BINANCE_USDS_FUTURES:
return DOMAIN_VENUE(BINANCE_USDS_FUTURES);
case api::VENUE_COINBASE:
return DOMAIN_VENUE(COINBASE);
case api::VENUE_ICE:
return DOMAIN_VENUE(ICE);
case bts::api::VENUE_OKX:
return DOMAIN_VENUE(OKX);
default: {
LOG(md, Error, "convert unknown venue: {}", static_cast<int>(venue));
break;
}
}
return DOMAIN_VENUE(UNSPECIFIED);
}
bts::api::Venue DomainSecurityUtils::convert(api::domain::Venue venue) {
switch (venue) {
case DOMAIN_VENUE(GLBX):
return api::Venue::VENUE_GLBX;
case DOMAIN_VENUE(DERIBIT):
return api::Venue::VENUE_DERIBIT;
case DOMAIN_VENUE(CBOE):
return api::Venue::VENUE_CBOE;
case DOMAIN_VENUE(TAIFEX):
return api::Venue::VENUE_TAIFEX;
case DOMAIN_VENUE(FTX):
return api::Venue::VENUE_FTX;
case DOMAIN_VENUE(BINANCE):
return api::Venue::VENUE_BINANCE;
case DOMAIN_VENUE(BINANCE_COIN_FUTURES):
return api::Venue::VENUE_BINANCE_COIN_FUTURES;
case DOMAIN_VENUE(BINANCE_US):
return api::Venue::VENUE_BINANCE_US;
case DOMAIN_VENUE(BINANCE_USDS_FUTURES):
return api::Venue::VENUE_BINANCE_USDS_FUTURES;
case DOMAIN_VENUE(OKX):
return api::Venue::VENUE_OKX;
case DOMAIN_VENUE(SIM):
return api::Venue::VENUE_SIM;
case DOMAIN_VENUE(COINBASE):
return api::Venue::VENUE_COINBASE;
case DOMAIN_VENUE(UNSPECIFIED):
return api::VENUE_UNSET;
default:
bts_assert(false);
return api::Venue::VENUE_UNSET;
}
}
bts::api::domain::SecurityType DomainSecurityUtils::convert(
bts::api::SecurityType sec_type) {
switch (sec_type) {
case bts::api::SecurityType::SECURITYTYPE_UNSET:
return DOMAIN_SEC_TYPE(UNSPECIFIED);
case bts::api::SecurityType::SECURITYTYPE_SPOT:
return DOMAIN_SEC_TYPE(SPOT);
case bts::api::SecurityType::SECURITYTYPE_OPTION:
return DOMAIN_SEC_TYPE(OPTION);
case bts::api::SecurityType::SECURITYTYPE_FUTURE:
return DOMAIN_SEC_TYPE(FUTURE);
case bts::api::SecurityType::SECURITYTYPE_SPREAD:
return DOMAIN_SEC_TYPE(SPREAD);
case bts::api::SecurityType::SECURITYTYPE_SYNTHETIC:
return DOMAIN_SEC_TYPE(SYNTHETIC);
default:
return DOMAIN_SEC_TYPE(UNSPECIFIED);
}
}
bts::domain::FutureSecurity DomainSecurityUtils::convert(
const bts::api::FutureContract &fut) {
bts::core::TimeStamp ts(
fut.expiration_year(), fut.expiration_month(), fut.expiration_day());
return {ts};
}
bts::domain::OptionSecurity DomainSecurityUtils::convert(
const bts::api::OptionContract &opt) {
bts::core::TimeStamp ts(
opt.expiration_year(), opt.expiration_month(), opt.expiration_day());
return {
ts, Price::from_double(opt.strike()),
opt.call_put() == bts::api::PUTORCALL_CALL
? bts::api::domain::CallPut::CALL
: bts::api::domain::CallPut::PUT};
}
bts::domain::SpreadSecurity DomainSecurityUtils::convert(
const bts::api::SpreadContract &spr) {
bts::domain::SpreadSecurity rv = {};
for (const auto &leg : spr.legs()) {
bts::domain::LegDefinition leg_d{
bts::domain::SecurityID(leg.security().id()),
bts::domain::Quantity(leg.quantity()),
leg.side() == bts::api::SIDE_BUY ? bts::domain::Side::Value::Buy
: bts::domain::Side::Value::Sell};
rv.legs.push_back(leg_d);
}
return rv;
}
bts::api::SecurityType DomainSecurityUtils::get_type(
const bts::api::Security &s) {
switch (s.Contract_case()) {
case bts::api::Security::ContractCase::CONTRACT_NOT_SET:
return bts::api::SecurityType::SECURITYTYPE_UNSET;
case bts::api::Security::ContractCase::kFuture:
return bts::api::SecurityType::SECURITYTYPE_FUTURE;
case bts::api::Security::ContractCase::kOption:
return bts::api::SecurityType::SECURITYTYPE_OPTION;
case bts::api::Security::ContractCase::kSpread:
return bts::api::SecurityType::SECURITYTYPE_SPREAD;
case bts::api::Security::ContractCase::kSynthetic:
return bts::api::SecurityType::SECURITYTYPE_SYNTHETIC;
case bts::api::Security::ContractCase::kSpot:
return bts::api::SECURITYTYPE_SPOT;
default:
bts_assert(false);
return bts::api::SecurityType::SECURITYTYPE_UNSET;
}
return bts::api::SecurityType::SECURITYTYPE_UNSET;
}
std::string DomainSecurityUtils::get_exchange_id(const bts::api::Security &s) {
std::string rv;
bts_assert(get_security_desc(s, rv));
return rv;
}
bool DomainSecurityUtils::get_security_desc(
const bts::api::Security &security, std::string &desc) {
switch (security.ExchangeData_case()) {
case bts::api::Security::ExchangeDataCase::kCboe:
desc = security.cboe().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kTaifex:
desc = security.taifex().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kCfe:
desc = security.cfe().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kDeribit:
desc = security.deribit().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kGlbx:
desc = security.glbx().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kIce:
desc = security.ice().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kBinance:
desc = security.binance().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kBinanceCoinFutures:
desc = security.binance_coin_futures().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kBinanceUs:
desc = security.binance_us().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kCoinbase:
desc = security.coinbase().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kBinanceUsdsFutures:
desc = security.binance_usds_futures().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kOkx:
desc = security.okx().security_desc();
break;
case bts::api::Security::ExchangeDataCase::kFtx:
desc = security.ftx().security_desc();
break;
default:
if (security.has_synthetic()) {
desc = security.synthetic().name();
break;
}
return false;
}
return true;
}
domain::Price DomainSecurityUtils::convert(md::IntPrice iprice) {
int64_t mantissa = iprice.mantissa();
int8_t exp_diff = iprice.exponent() - domain::Price::exponent();
if (exp_diff != 0) {
mantissa *= std::pow(10, exp_diff);
}
return domain::Price{mantissa};
}
BookLevel DomainSecurityUtils::convert(md::PriceSize ps) {
BookLevel rv;
convert(ps, rv);
return rv;
}
void DomainSecurityUtils::convert(md::PriceSize ps, BookLevel &res) {
res.price = convert(ps.int_price());
res.total_quantity.value() = ps.size();
res.direct_quantity.value() = ps.direct_size();
res.n_orders = 0;
}
void DomainSecurityUtils::convert(
const bts::domain::BookSide &book_side,
bts::md::PriceSize *res,
size_t res_size) {
convert(book_side.data(), book_side.size(), res, res_size);
}
void DomainSecurityUtils::convert(
const BookLevel *book_side,
size_t size,
md::PriceSize *res,
size_t res_size) {
size_t sz = std::min(size, res_size);
size_t i = 0;
for (; i < sz; i++) {
// WARNING: Implied size is discarded here. There would be data loss anyways, since
// bts::md::PriceSize's implied size is a uint, and domain::BookLevel's is a float.
res[i] = md::PriceSize{
md::IntPrice{
book_side[i].price.mantissa(), book_side[i].price.exponent()},
book_side[i].total_quantity.value()};
}
// Set remaining levels to empty.
for (; i < res_size; i++) {
res[i] = bts::md::PriceSize{};
}
}
void DomainSecurityUtils::convert(
const md::PriceSize *book_side, std::size_t len, BookSide &res) {
if (res.size() < len) {
len = res.size();
}
while (len-- != 0) {
convert(book_side[len], res[len]);
}
}
void DomainSecurityUtils::convert(
const co2::TradeMessage &tm, TradeRecord &tr) {
tr.sec_id.value() = tm.key();
tr.time_stamp = core::TimeStamp::from_nanos(tm.time());
tr.agg_side = tm.aggressor_side() == co2::AggressorSide::AGGRESSOR_SIDE_BUY
? AggressorSide::Buy
: AggressorSide::Sell;
tr.trade_quantity.value() = tm.size();
tr.trade_price =
convert(md::IntPrice{tm.mantissa(), static_cast<int8_t>(tm.exponent())});
}
} // namespace bts::domain