2184 lines
85 KiB
C++
2184 lines
85 KiB
C++
#include "lib/api/service_helpers/AdminServiceUtils.h"
|
|
#include "lib/api/services/AdminService.server.pb.h"
|
|
#include "lib/config/config.h"
|
|
#include "lib/config/protos/cme_reference_data.pb.h"
|
|
#include "lib/config/protos/deployment_type.pb.h"
|
|
#include "lib/config/protos/jetfix.pb.h"
|
|
#include "lib/domain/DomainSecurityUtils.h"
|
|
#include "lib/domain/SecurityCriteria.h"
|
|
#include "lib/domain_model/Security.pb.h"
|
|
#include "lib/md/SymbolLoader.h"
|
|
|
|
#include <boost/algorithm/string/case_conv.hpp>
|
|
#include <boost/algorithm/string/predicate.hpp>
|
|
#include <set>
|
|
#include <sstream>
|
|
|
|
namespace bts {
|
|
namespace admin {
|
|
|
|
using namespace bts::api::admin;
|
|
using namespace bts::api::orderman;
|
|
|
|
using bts::api::Venue;
|
|
using bts::domain::DomainSecurityUtils;
|
|
using bts::domain::SecurityCriteria;
|
|
using bts::md::SymbolLoader;
|
|
using bts::md::UserSymbol;
|
|
using std::set;
|
|
using std::size_t;
|
|
using std::vector;
|
|
|
|
////////////////////////////////////////////
|
|
// connection accessors ////////////////////
|
|
////////////////////////////////////////////
|
|
uint32_t AdminServiceUtils::find_max_connection_id(const AdminData &data) {
|
|
uint32_t rv = 0;
|
|
for (const auto &conn : data.connections())
|
|
if (conn.id() > rv)
|
|
rv = conn.id();
|
|
return rv;
|
|
}
|
|
const ExchangeConnection *AdminServiceUtils::find_connection(
|
|
const AdminData &data, const std::string &connection_name) {
|
|
for (const auto &connection : data.connections())
|
|
if (connection.name() == connection_name)
|
|
return &connection;
|
|
return nullptr;
|
|
}
|
|
bool AdminServiceUtils::has_exchange(
|
|
const ExchangeConnection &conn, api::Venue exchange) {
|
|
bool rv = false;
|
|
switch (exchange) {
|
|
case api::Venue::VENUE_GLBX:
|
|
rv = conn.has_cme_connection() &&
|
|
(conn.cme_connection().has_cgw_connection() ||
|
|
conn.cme_connection().has_msgw_connection());
|
|
break;
|
|
case api::Venue::VENUE_UNSET:
|
|
case api::Venue::VENUE_SIM:
|
|
case api::Venue::VENUE_SIMICE:
|
|
rv = conn.has_sim_connection();
|
|
break;
|
|
case api::Venue::VENUE_ICE:
|
|
rv = conn.has_ice_connection();
|
|
break;
|
|
case api::Venue::VENUE_DERIBIT: // TODO
|
|
case api::Venue::VENUE_FTX:
|
|
case api::Venue::VENUE_BINANCE:
|
|
case api::Venue::VENUE_BINANCE_COIN_FUTURES:
|
|
case api::Venue::VENUE_BINANCE_US:
|
|
case api::Venue::VENUE_COINBASE:
|
|
case api::Venue::VENUE_BINANCE_USDS_FUTURES:
|
|
case api::Venue::VENUE_OKX:
|
|
case api::Venue::VENUE_BTS:
|
|
case api::Venue::VENUE_CBOE:
|
|
case api::Venue::VENUE_TAIFEX:
|
|
case api::Venue::VENUE_CBOECFE:
|
|
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
|
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
|
rv = false;
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
const ExchangeConnection *AdminServiceUtils::find_default_account_connection(
|
|
const AdminData &data,
|
|
const BTSAccount &account,
|
|
bts::api::Venue exchange) {
|
|
// todo:get from parent accounts if not overridden
|
|
if (account.has_connections())
|
|
for (const std::string &conn_name :
|
|
account.connections().exchange_connection_names()) {
|
|
const ExchangeConnection *conn = find_connection(data, conn_name);
|
|
if (conn != nullptr && has_exchange(*conn, exchange))
|
|
return conn;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const ExchangeConnection *AdminServiceUtils::resolve_cme_connection(
|
|
const AdminData &data,
|
|
const BTSAccount &account,
|
|
const bts::api::Security &sec) {
|
|
if (account.has_connections())
|
|
for (const std::string &conn_name :
|
|
account.connections().exchange_connection_names()) {
|
|
const ExchangeConnection *conn = find_connection(data, conn_name);
|
|
if (conn != nullptr && conn->has_cme_connection())
|
|
if (conn->cme_connection().has_cgw_connection() ||
|
|
(sec.has_glbx() &&
|
|
conn->cme_connection().has_msgw_connection() &&
|
|
conn->cme_connection().msgw_connection().market_segment_id() ==
|
|
sec.glbx().market_segment_id()))
|
|
return conn;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::ExchangeConnection *
|
|
AdminServiceUtils::resolve_ice_connection(
|
|
const bts::api::admin::AdminData &data,
|
|
const bts::api::admin::BTSAccount &account,
|
|
const bts::api::Security &) {
|
|
if (account.has_connections()) {
|
|
for (const std::string &conn_name :
|
|
account.connections().exchange_connection_names()) {
|
|
const bts::api::admin::ExchangeConnection *conn =
|
|
find_connection(data, conn_name);
|
|
if (conn != nullptr && conn->has_ice_connection())
|
|
return conn;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::ExchangeConnection *
|
|
AdminServiceUtils::resolve_sim_connection(
|
|
const bts::api::admin::AdminData &data,
|
|
const bts::api::admin::BTSAccount &account,
|
|
const bts::api::Security &) {
|
|
if (account.has_connections())
|
|
for (const std::string &conn_name :
|
|
account.connections().exchange_connection_names()) {
|
|
const bts::api::admin::ExchangeConnection *conn =
|
|
find_connection(data, conn_name);
|
|
if (conn != nullptr && conn->has_sim_connection())
|
|
return conn;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::ExchangeConnection *
|
|
AdminServiceUtils::resolve_connection(
|
|
const bts::api::admin::AdminData &data,
|
|
const bts::api::admin::BTSAccount &account,
|
|
const bts::api::Security &sec) {
|
|
const bts::api::admin::ExchangeConnection *rv = nullptr;
|
|
switch (sec.exchange()) {
|
|
case api::Venue::VENUE_GLBX: {
|
|
//CME EXECUTION NEEDS TO BE UPDATED, probably merge with VENUE_BINANCE_USDS_FUTURES
|
|
|
|
auto deployment_type =
|
|
boost::to_lower_copy(config::get<config::DeploymentType>().type());
|
|
rv = resolve_cme_connection(data, account, sec);
|
|
if (rv == nullptr &&
|
|
(deployment_type == "dev" || deployment_type == "demo"))
|
|
rv = resolve_sim_connection(data, account, sec);
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_ICE: {
|
|
rv = resolve_ice_connection(data, account, sec);
|
|
auto deployment_type =
|
|
boost::to_lower_copy(config::get<config::DeploymentType>().type());
|
|
if (rv == nullptr &&
|
|
(deployment_type == "dev" || deployment_type == "demo"))
|
|
rv = resolve_sim_connection(data, account, sec);
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_UNSET:
|
|
case api::Venue::VENUE_BTS:
|
|
case api::Venue::VENUE_SIM:
|
|
case api::Venue::VENUE_SIMICE:
|
|
rv = resolve_sim_connection(data, account, sec);
|
|
break;
|
|
case api::Venue::VENUE_DERIBIT:
|
|
case api::Venue::VENUE_FTX:
|
|
case api::Venue::VENUE_OKX:
|
|
case api::Venue::VENUE_BINANCE:
|
|
case api::Venue::VENUE_BINANCE_COIN_FUTURES:
|
|
case api::Venue::VENUE_BINANCE_US:
|
|
case api::Venue::VENUE_COINBASE:
|
|
case api::Venue::VENUE_TAIFEX:
|
|
case api::Venue::VENUE_CBOE:
|
|
case api::Venue::VENUE_BINANCE_USDS_FUTURES: {
|
|
if (account.has_connections())
|
|
for (const std::string &conn_name :
|
|
account.connections().exchange_connection_names()) {
|
|
const bts::api::admin::ExchangeConnection *conn =
|
|
find_connection(data, conn_name);
|
|
if (conn != nullptr && conn->has_general_connection())
|
|
return conn;
|
|
}
|
|
return nullptr;
|
|
}
|
|
case api::Venue::VENUE_CBOECFE:
|
|
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
|
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
|
rv = nullptr;
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
////////////////////////////////////////////
|
|
// connection mutators /////////////////////
|
|
////////////////////////////////////////////
|
|
bts::api::admin::ExchangeConnection *AdminServiceUtils::add_connection(
|
|
bts::api::admin::AdminData &data,
|
|
const bts::api::admin::ExchangeConnection &new_connection) {
|
|
auto new_connection_ptr = data.add_connections();
|
|
new_connection_ptr->CopyFrom(new_connection);
|
|
return new_connection_ptr;
|
|
}
|
|
void AdminServiceUtils::fill_connections_from_config(
|
|
bts::api::admin::AdminData &admin_data) {
|
|
admin_data.clear_connections();
|
|
auto &all_connections = config::get<config::JetFIX>().connection();
|
|
for (auto const &c : all_connections) {
|
|
bts::api::admin::ExchangeConnection connection;
|
|
uint32_t new_id = find_max_connection_id(admin_data) + 1;
|
|
connection.set_id(new_id);
|
|
connection.set_name(c.name());
|
|
|
|
switch (c.venue()) {
|
|
//CME EXECUTION NEEDS TO BE UPDATED, probably merge default case
|
|
case bts::api::VENUE_GLBX:
|
|
if (c.cme_market_segment_id() == 0)
|
|
connection.mutable_cme_connection()->mutable_cgw_connection();
|
|
else
|
|
connection.mutable_cme_connection()
|
|
->mutable_msgw_connection()
|
|
->set_market_segment_id(c.cme_market_segment_id());
|
|
add_connection(admin_data, connection);
|
|
break;
|
|
|
|
case bts::api::VENUE_SIM:
|
|
case bts::api::VENUE_SIMICE:
|
|
connection.mutable_sim_connection();
|
|
add_connection(admin_data, connection);
|
|
break;
|
|
case bts::api::VENUE_ICE:
|
|
connection.mutable_ice_connection()->set_sender_compid(
|
|
c.sender_compid());
|
|
add_connection(admin_data, connection);
|
|
break;
|
|
case bts::api::VENUE_TAIFEX:
|
|
case bts::api::VENUE_CBOE:
|
|
default:
|
|
connection.mutable_general_connection()->set_exchange(c.venue());
|
|
add_connection(admin_data, connection);
|
|
break;
|
|
}
|
|
}
|
|
for (int i = 0; i < admin_data.accounts_size(); i++)
|
|
sync_account_connections(admin_data, *admin_data.mutable_accounts(i));
|
|
}
|
|
////////////////////////////////////////////
|
|
// account accessors ///////////////////////
|
|
////////////////////////////////////////////
|
|
BTSAccount *AdminServiceUtils::find_account(
|
|
AdminData &data, const std::string &name, bool include_deleted) {
|
|
auto account_ptrs = accounts_mutable(data, include_deleted);
|
|
for (auto account_ptr : account_ptrs)
|
|
if (name == account_ptr->name())
|
|
return account_ptr;
|
|
return nullptr;
|
|
}
|
|
std::map<std::string, uint32_t> AdminServiceUtils::get_clearing_account_map(
|
|
const AdminData &data) {
|
|
std::map<std::string, uint32_t> rv;
|
|
auto all_accounts = accounts(data, true);
|
|
for (BTSAccount const *a : all_accounts) {
|
|
// only for CME, ICE, GLBX
|
|
AdminServiceOperationResult res;
|
|
// cme
|
|
{
|
|
auto cme_clr_acc = find_account_exchange_account(
|
|
data, *a, api::Venue::VENUE_GLBX, res);
|
|
if (res.is_success())
|
|
rv[cme_clr_acc] = a->id();
|
|
}
|
|
// ice
|
|
{
|
|
auto ice_clr_acc = find_account_exchange_account(
|
|
data, *a, api::Venue::VENUE_ICE, res);
|
|
if (res.is_success())
|
|
rv[ice_clr_acc] = a->id();
|
|
}
|
|
// sim
|
|
{
|
|
auto sim_clr_acc = find_account_exchange_account(
|
|
data, *a, api::Venue::VENUE_SIM, res);
|
|
if (res.is_success())
|
|
rv[sim_clr_acc] = a->id();
|
|
}
|
|
}
|
|
return rv;
|
|
}
|
|
const BTSAccount *AdminServiceUtils::find_account(
|
|
const AdminData &data, const std::string &name, bool include_deleted) {
|
|
auto account_ptrs = accounts(data, include_deleted);
|
|
for (auto account_ptr : account_ptrs)
|
|
if (name == account_ptr->name())
|
|
return account_ptr;
|
|
return nullptr;
|
|
}
|
|
|
|
BTSAccount const *AdminServiceUtils::find_account(
|
|
const AdminData &data,
|
|
const std::string &clearing_account,
|
|
bts::api::Venue exchange) {
|
|
auto all_accounts = accounts(data, true);
|
|
for (BTSAccount const *a : all_accounts) {
|
|
AdminServiceOperationResult res;
|
|
// returns the first account that matches
|
|
std::string s = find_account_exchange_account(data, *a, exchange, res);
|
|
if (res.is_success() && s == clearing_account)
|
|
return a;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
BTSAccount *AdminServiceUtils::find_account(
|
|
AdminData &data, uint32_t id, bool include_deleted) {
|
|
auto account_ptrs = accounts_mutable(data, include_deleted);
|
|
for (auto account_ptr : account_ptrs)
|
|
if (id == account_ptr->id())
|
|
return account_ptr;
|
|
return nullptr;
|
|
}
|
|
const BTSAccount *AdminServiceUtils::find_account(
|
|
const AdminData &data, uint32_t id, bool include_deleted) {
|
|
auto account_ptrs = accounts(data, include_deleted);
|
|
for (auto account_ptr : account_ptrs)
|
|
if (id == account_ptr->id())
|
|
return account_ptr;
|
|
return nullptr;
|
|
}
|
|
std::vector<const BTSAccount *> AdminServiceUtils::accounts(
|
|
const AdminData &data, bool include_deleted) {
|
|
std::vector<const BTSAccount *> rv;
|
|
for (const auto &account : data.accounts())
|
|
if (account.is_present() || include_deleted)
|
|
rv.push_back(&account);
|
|
return rv;
|
|
}
|
|
std::vector<bts::api::admin::BTSAccount *> AdminServiceUtils::accounts_mutable(
|
|
bts::api::admin::AdminData &data, bool include_deleted) {
|
|
std::vector<bts::api::admin::BTSAccount *> rv;
|
|
for (int i = 0; i < data.accounts_size(); i++) {
|
|
bts::api::admin::BTSAccount *account_ptr = data.mutable_accounts(i);
|
|
if (account_ptr->is_present() || include_deleted)
|
|
rv.push_back(account_ptr);
|
|
}
|
|
return rv;
|
|
}
|
|
uint32_t AdminServiceUtils::find_max_acct_id(
|
|
const bts::api::admin::AdminData &data) {
|
|
uint32_t rv = 0;
|
|
for (const auto &acct : data.accounts())
|
|
if (acct.id() > rv)
|
|
rv = acct.id();
|
|
return rv;
|
|
}
|
|
const CMEAccountData *AdminServiceUtils::get_account_cme_data(
|
|
const BTSAccount &account, const AdminData &data) {
|
|
if (account.has_exchange_account_data() &&
|
|
account.exchange_account_data().has_cme_account_data())
|
|
return &(account.exchange_account_data().cme_account_data());
|
|
else if (has_id(account.parent_account_id())) {
|
|
const BTSAccount *parent_account =
|
|
find_account(data, account.parent_account_id());
|
|
if (parent_account != nullptr)
|
|
return get_account_cme_data(*parent_account, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const ICEAccountData *AdminServiceUtils::get_account_ice_data(
|
|
const BTSAccount &account, const AdminData &data) {
|
|
if (account.has_exchange_account_data() &&
|
|
account.exchange_account_data().has_ice_account_data())
|
|
return &(account.exchange_account_data().ice_account_data());
|
|
else if (has_id(account.parent_account_id())) {
|
|
const BTSAccount *parent_account =
|
|
find_account(data, account.parent_account_id());
|
|
if (parent_account != nullptr)
|
|
return get_account_ice_data(*parent_account, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::SIMAccountData *AdminServiceUtils::get_account_sim_data(
|
|
const bts::api::admin::BTSAccount &account,
|
|
const bts::api::admin::AdminData &data) {
|
|
if (account.has_exchange_account_data() &&
|
|
account.exchange_account_data().has_sim_account_data())
|
|
return &(account.exchange_account_data().sim_account_data());
|
|
else if (has_id(account.parent_account_id())) {
|
|
const bts::api::admin::BTSAccount *parent_account =
|
|
find_account(data, account.parent_account_id());
|
|
if (parent_account != nullptr)
|
|
return get_account_sim_data(*parent_account, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool AdminServiceUtils::account_has_connection(
|
|
const BTSAccount &account, const std::string &connection_name) {
|
|
if (account.has_connections()) {
|
|
for (int i = 0;
|
|
i < account.connections().exchange_connection_names_size(); i++)
|
|
if (connection_name ==
|
|
account.connections().exchange_connection_names(i))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
std::string AdminServiceUtils::find_account_exchange_account(
|
|
const AdminData &data,
|
|
const BTSAccount &account,
|
|
api::Venue exchange,
|
|
AdminServiceOperationResult &out_result) {
|
|
out_result.set_is_success(true);
|
|
std::string rv = "";
|
|
switch (exchange) {
|
|
case api::Venue::VENUE_GLBX: {
|
|
auto cme_account_data = get_account_cme_data(account, data);
|
|
if (cme_account_data != nullptr)
|
|
rv = cme_account_data->clearing_account();
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_ICE: {
|
|
auto ice_account_data = get_account_ice_data(account, data);
|
|
if (ice_account_data != nullptr)
|
|
rv = ice_account_data->clearing_account();
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_SIM:
|
|
case api::Venue::VENUE_SIMICE: {
|
|
auto sim_account_data = get_account_sim_data(account, data);
|
|
if (sim_account_data != nullptr)
|
|
rv = sim_account_data->clearing_account();
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_UNSET:
|
|
case api::Venue::VENUE_DERIBIT: // TODO
|
|
case api::Venue::VENUE_FTX: // TODO
|
|
case api::Venue::VENUE_BINANCE: // TODO
|
|
case api::Venue::VENUE_BINANCE_COIN_FUTURES:
|
|
case api::Venue::VENUE_BINANCE_US:
|
|
case api::Venue::VENUE_COINBASE:
|
|
case api::Venue::VENUE_BINANCE_USDS_FUTURES:
|
|
case api::Venue::VENUE_OKX:
|
|
case api::Venue::VENUE_BTS:
|
|
case api::Venue::VENUE_CBOE:
|
|
case api::Venue::VENUE_TAIFEX:
|
|
case api::Venue::VENUE_CBOECFE:
|
|
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
|
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Exchange not supported");
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
std::map<uint32_t, bool> AdminServiceUtils::accounts_map(
|
|
const bts::api::admin::AdminData &admin_data) {
|
|
std::map<uint32_t, bool> rv;
|
|
auto account_ptrs = accounts(admin_data, false);
|
|
for (const bts::api::admin::BTSAccount *account_ptr : account_ptrs)
|
|
rv.insert(std::pair<uint32_t, bool>(
|
|
account_ptr->id(), account_ptr->is_active()));
|
|
return rv;
|
|
}
|
|
void AdminServiceUtils::validate_account_update(
|
|
const bts::api::admin::AdminData &admin_data,
|
|
const bts::api::admin::BTSAccount &updated_account,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
result.set_is_success(true);
|
|
// validate id
|
|
if (find_account(admin_data, updated_account.id()) == nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Could not find account id");
|
|
return;
|
|
}
|
|
// validate that name change doesnt collide
|
|
auto account_ptrs = accounts(admin_data, false);
|
|
for (const bts::api::admin::BTSAccount *account_ptr : account_ptrs)
|
|
if (account_ptr->id() != updated_account.id() &&
|
|
account_ptr->name() == updated_account.name()) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Account by this name already exists");
|
|
return;
|
|
}
|
|
// validate account exchange changes
|
|
validate_account_exchange_data(updated_account, result);
|
|
}
|
|
void AdminServiceUtils::validate_account_exchange_data(
|
|
const bts::api::admin::BTSAccount &account,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
result.set_is_success(true);
|
|
if (account.has_exchange_account_data()) {
|
|
if (account.exchange_account_data().has_cme_account_data()) {
|
|
const bts::api::admin::CMEAccountData &cme_account_data =
|
|
account.exchange_account_data().cme_account_data();
|
|
if (cme_account_data.clearing_account().size() > 12) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("CME account can not be more "
|
|
"12 characters long");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(
|
|
const bts::api::admin::AdminData &data,
|
|
const std::string &account_name,
|
|
const std::string &user_name,
|
|
const bts::api::Security &sec,
|
|
bts::api::admin::AdminServiceOperationResult &out_result) {
|
|
bts::api::orderman::RoutingRecord rv;
|
|
const bts::api::admin::BTSAccount *account_ptr =
|
|
find_account(data, account_name);
|
|
if (account_ptr == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find account");
|
|
return rv;
|
|
}
|
|
const bts::api::admin::BTSUser *user_ptr = find_user(data, user_name);
|
|
if (user_ptr == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find user");
|
|
return rv;
|
|
}
|
|
return get_routing_record(
|
|
data, account_ptr->id(), user_ptr->id(), sec, out_result);
|
|
}
|
|
bts::api::orderman::RoutingRecord AdminServiceUtils::get_routing_record(
|
|
const bts::api::admin::AdminData &data,
|
|
uint32_t account_id,
|
|
uint32_t user_id,
|
|
const bts::api::Security &sec,
|
|
bts::api::admin::AdminServiceOperationResult &out_result) {
|
|
bts::api::orderman::RoutingRecord rv;
|
|
out_result.set_is_success(true);
|
|
const bts::api::admin::BTSAccount *account_ptr =
|
|
find_account(data, account_id);
|
|
if (account_ptr == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find account");
|
|
return rv;
|
|
}
|
|
const bts::api::admin::BTSUser *user_ptr = find_user(data, user_id);
|
|
if (user_ptr == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find user");
|
|
return rv;
|
|
}
|
|
const bts::api::admin::ExchangeConnection
|
|
*conn_ptr = // find_default_account_connection(data, *account_ptr,
|
|
// sec.exchange());
|
|
resolve_connection(data, *account_ptr, sec);
|
|
if (conn_ptr == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find connection");
|
|
return rv;
|
|
}
|
|
switch (sec.exchange()) {
|
|
case api::Venue::VENUE_CBOE:{//subaccount not added
|
|
rv.set_session("cboe_1");
|
|
rv.set_account(account_ptr->name());
|
|
rv.set_operator_id(user_ptr->name());
|
|
out_result.set_is_success(true);
|
|
return rv;
|
|
}
|
|
case api::VENUE_OKX: {
|
|
rv.set_session("okx_1");
|
|
rv.set_account(account_ptr->name());
|
|
rv.set_operator_id(user_ptr->name());
|
|
// AdminServiceUtils::ExchangeSubAccountResolver resolver;
|
|
// auto sub_acc_ptr = resolver.find_entry(&sec, account_ptr->name(), true);
|
|
// if (!sub_acc_ptr) {
|
|
// out_result.set_is_success(false);
|
|
// out_result.set_error_text("Could not resolve sub account");
|
|
// return rv;
|
|
// }
|
|
// rv.set_account_code(sub_acc_ptr->exchange_subaccount());
|
|
out_result.set_is_success(true);
|
|
return rv;
|
|
}
|
|
case api::Venue::VENUE_DERIBIT: {
|
|
rv.set_session("deribit_1");
|
|
rv.set_account(account_ptr->name());
|
|
rv.set_operator_id(user_ptr->name());
|
|
AdminServiceUtils::ExchangeSubAccountResolver resolver;
|
|
auto sub_acc_ptr = resolver.find_entry(&sec, account_ptr->name(), true);
|
|
if (!sub_acc_ptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not resolve sub account");
|
|
return rv;
|
|
}
|
|
rv.set_account_code(sub_acc_ptr->exchange_subaccount());
|
|
out_result.set_is_success(true);
|
|
return rv;
|
|
}
|
|
case api::Venue::VENUE_ICE: {
|
|
const bts::api::admin::ICEUserData *ice_user_data =
|
|
get_user_ice_data(*user_ptr, data);
|
|
if (ice_user_data == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find ICE data for user");
|
|
return rv;
|
|
}
|
|
const bts::api::admin::ICEAccountData *ice_account_data =
|
|
get_account_ice_data(*account_ptr, data);
|
|
if (ice_account_data == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find ICE data for account");
|
|
return rv;
|
|
}
|
|
// check for data corectness
|
|
if (ice_user_data->operator_id().length() == 0) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Operator ID is not set");
|
|
return rv;
|
|
}
|
|
|
|
rv.set_session(conn_ptr->name());
|
|
rv.set_sender_compid(conn_ptr->ice_connection().sender_compid());
|
|
rv.set_account(ice_account_data->clearing_account());
|
|
rv.set_operator_id(ice_user_data->operator_id());
|
|
rv.set_cti_code(ice_account_data->cti());
|
|
rv.set_customer_or_firm(ice_account_data->origin());
|
|
rv.set_clearing_firm(ice_account_data->clearing_firm());
|
|
rv.set_customer_account_ref_id(
|
|
ice_account_data->customer_account_ref_id());
|
|
rv.set_account_code(ice_account_data->account_code());
|
|
rv.set_company_id(std::to_string(ice_user_data->company_id()));
|
|
rv.set_authorized_trader(ice_user_data->authorized_trader());
|
|
rv.set_authorized_group(ice_user_data->authorized_group());
|
|
rv.set_cust_order_handing_inst(ice_user_data->cust_order_handing_inst());
|
|
|
|
return rv;
|
|
}
|
|
case bts::api::Venue::VENUE_GLBX: {
|
|
const bts::api::admin::CMEUserData *cme_user_data =
|
|
get_user_cme_data(*user_ptr, data);
|
|
if (cme_user_data == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text(
|
|
"Could not find CME data for user"); // CME or globex ?
|
|
return rv;
|
|
}
|
|
const bts::api::admin::CMEAccountData *cme_account_data =
|
|
get_account_cme_data(*account_ptr, data);
|
|
if (cme_account_data == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find CME data for account");
|
|
return rv;
|
|
}
|
|
// check for data corectness
|
|
if (cme_user_data->operator_id().length() == 0) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Operator ID is not set");
|
|
return rv;
|
|
}
|
|
if (cme_user_data->location().length() == 0) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Location is not set");
|
|
return rv;
|
|
}
|
|
if (cme_account_data->clearing_account().length() == 0) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Clearing Account is not set");
|
|
return rv;
|
|
}
|
|
if (cme_account_data->cti() ==
|
|
bts::api::orderman::CTICode::CTI_CODE_UNDEFINED) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("CTI Code is not set");
|
|
return rv;
|
|
}
|
|
rv.set_session(conn_ptr->name());
|
|
rv.set_operator_id(cme_user_data->operator_id());
|
|
rv.set_location(cme_user_data->location());
|
|
|
|
rv.set_smp_id(cme_user_data->smp_id());
|
|
|
|
if (cme_user_data->smp_instruction() == "O")
|
|
rv.set_smp_instruction(
|
|
api::orderman::SelfMatchPreventionInstruction::
|
|
SELF_MATCH_PREVENTION_INSTRUCTION_CANCEL_RESTING);
|
|
else if (cme_user_data->smp_instruction() == "N")
|
|
rv.set_smp_instruction(
|
|
api::orderman::SelfMatchPreventionInstruction::
|
|
SELF_MATCH_PREVENTION_INSTRUCTION_CANCEL_AGRESSING);
|
|
else
|
|
rv.set_smp_instruction(
|
|
api::orderman::SelfMatchPreventionInstruction::
|
|
SELF_MATCH_PREVENTION_INSTRUCTION_UNDEFINED);
|
|
|
|
rv.set_account(cme_account_data->clearing_account());
|
|
rv.set_cti_code(cme_account_data->cti());
|
|
rv.set_customer_or_firm(cme_account_data->origin());
|
|
return rv;
|
|
}
|
|
case api::Venue::VENUE_SIM:
|
|
case api::Venue::VENUE_SIMICE: {
|
|
const bts::api::admin::SIMUserData *sim_user_data =
|
|
get_user_sim_data(*user_ptr, data);
|
|
if (sim_user_data == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find SIM data for user");
|
|
return rv;
|
|
}
|
|
const bts::api::admin::SIMAccountData *sim_account_data =
|
|
get_account_sim_data(*account_ptr, data);
|
|
if (sim_account_data == nullptr) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Could not find SIM data for account");
|
|
return rv;
|
|
}
|
|
// check for data corectness
|
|
if (sim_user_data->operator_id().length() == 0) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Operator ID is not set");
|
|
return rv;
|
|
}
|
|
if (sim_user_data->location().length() == 0) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Location is not set");
|
|
return rv;
|
|
}
|
|
if (sim_account_data->clearing_account().length() == 0) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Clearing Account is not set");
|
|
return rv;
|
|
}
|
|
if (sim_account_data->cti() ==
|
|
bts::api::orderman::CTICode::CTI_CODE_UNDEFINED) {
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("CTI Code is not set");
|
|
return rv;
|
|
}
|
|
rv.set_session(conn_ptr->name());
|
|
rv.set_operator_id(sim_user_data->operator_id());
|
|
rv.set_location(sim_user_data->location());
|
|
rv.set_account(sim_account_data->clearing_account());
|
|
rv.set_cti_code(sim_account_data->cti());
|
|
rv.set_customer_or_firm(sim_account_data->origin());
|
|
return rv;
|
|
} break;
|
|
case api::Venue::VENUE_TAIFEX:{
|
|
rv.set_session("taifex_1");
|
|
rv.set_account(account_ptr->name());
|
|
rv.set_operator_id(user_ptr->name());
|
|
out_result.set_is_success(true);
|
|
return rv;
|
|
}
|
|
case api::VENUE_BINANCE_USDS_FUTURES: {
|
|
rv.set_session("binance_usds_futures_1");
|
|
rv.set_account(account_ptr->name());
|
|
rv.set_account(user_ptr->name());
|
|
out_result.set_is_success(true);
|
|
return rv;
|
|
}
|
|
case api::VENUE_BINANCE: {
|
|
rv.set_session("binance_1");
|
|
rv.set_account(account_ptr->name());
|
|
rv.set_account(user_ptr->name());
|
|
out_result.set_is_success(true);
|
|
return rv;
|
|
}
|
|
case api::VENUE_FTX: // TODO
|
|
case api::VENUE_BINANCE_COIN_FUTURES:
|
|
case api::VENUE_BINANCE_US:
|
|
case api::Venue::VENUE_COINBASE:
|
|
case api::Venue::VENUE_UNSET:
|
|
case api::Venue::VENUE_BTS:
|
|
case api::Venue::VENUE_CBOECFE:
|
|
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
|
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Unsupported exchange");
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
////////////////////////////////////////////
|
|
// account mutators ////////////////////////
|
|
////////////////////////////////////////////
|
|
bts::api::admin::BTSAccount *AdminServiceUtils::create_account(
|
|
bts::api::admin::AdminData &data,
|
|
uint32_t parent_account_id,
|
|
const std::string &account_name,
|
|
const std::string &description,
|
|
bool is_active,
|
|
bts::api::admin::AdminServiceCreateAccountResult &result) {
|
|
result.set_is_success(true);
|
|
// the error conditions are checked first and returned immediatly
|
|
// i. account with the name already exists
|
|
// ii. parent account is set and does not exist
|
|
if (find_account(data, account_name, true) != nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Account by this name already exists");
|
|
return nullptr;
|
|
}
|
|
if (has_id(parent_account_id)) {
|
|
if (find_account(data, parent_account_id) == nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Parent group does not exist");
|
|
return nullptr;
|
|
}
|
|
}
|
|
uint32_t new_id = find_max_acct_id(data) + 1;
|
|
result.set_new_id(new_id);
|
|
bts::api::admin::BTSAccount *new_account_ptr = data.add_accounts();
|
|
new_account_ptr->set_is_present(true);
|
|
new_account_ptr->set_id(new_id);
|
|
new_account_ptr->set_parent_account_id(parent_account_id);
|
|
new_account_ptr->set_name(account_name);
|
|
new_account_ptr->set_description(description);
|
|
new_account_ptr->set_is_active(is_active);
|
|
new_account_ptr->mutable_risk_limit_enforcement()
|
|
->set_ignore_spread_position_limits(true);
|
|
return new_account_ptr;
|
|
}
|
|
void AdminServiceUtils::update_account(
|
|
bts::api::admin::AdminData &admin_data,
|
|
const bts::api::admin::BTSAccount &updated_account,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
validate_account_update(admin_data, updated_account, result);
|
|
if (result.is_success()) {
|
|
bts::api::admin::BTSAccount *account_ptr =
|
|
find_account(admin_data, updated_account.id());
|
|
account_ptr->CopyFrom(updated_account);
|
|
}
|
|
}
|
|
void AdminServiceUtils::delete_account(
|
|
bts::api::admin::AdminData &admin_data,
|
|
const bts::api::admin::IDAPIArgument &id,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
result.set_is_success(true);
|
|
api::admin::BTSAccount *account_ptr =
|
|
AdminServiceUtils::find_account(admin_data, id.id());
|
|
if (account_ptr != nullptr) {
|
|
std::string deleted_name;
|
|
int deleted_idx = 0;
|
|
do {
|
|
deleted_idx++;
|
|
deleted_name =
|
|
deleted_idx == 1
|
|
? fmt::format("DELETED_{}", account_ptr->name())
|
|
: fmt::format(
|
|
"DELETED_{}_{}", deleted_idx, account_ptr->name());
|
|
} while (AdminServiceUtils::find_account(
|
|
admin_data, deleted_name, true) != nullptr);
|
|
account_ptr->set_is_present(false);
|
|
account_ptr->set_name(deleted_name);
|
|
} else {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Could not find account");
|
|
}
|
|
}
|
|
void AdminServiceUtils::set_account_exchange_data(
|
|
bts::api::admin::BTSAccount *account,
|
|
const bts::api::admin::ExchangeAccountData &exchange_data) {
|
|
account->mutable_exchange_account_data()->CopyFrom(exchange_data);
|
|
}
|
|
void AdminServiceUtils::sync_account_connections(
|
|
const bts::api::admin::AdminData &data,
|
|
bts::api::admin::BTSAccount &account) {
|
|
if (account.has_connections()) {
|
|
std::map<std::string, bool> all_conn_names;
|
|
for (int i = 0; i < data.connections_size(); i++)
|
|
all_conn_names[data.connections(i).name()] = true;
|
|
std::vector<std::string> cleaned_connections;
|
|
for (int i = 0;
|
|
i < account.connections().exchange_connection_names_size(); i++) {
|
|
const std::string &conn_name =
|
|
account.connections().exchange_connection_names(i);
|
|
if (all_conn_names.find(conn_name) != all_conn_names.end())
|
|
cleaned_connections.push_back(conn_name);
|
|
}
|
|
account.mutable_connections()
|
|
->mutable_exchange_connection_names()
|
|
->Clear();
|
|
for (auto it = cleaned_connections.begin();
|
|
it != cleaned_connections.end(); it++)
|
|
account.mutable_connections()->add_exchange_connection_names(*it);
|
|
}
|
|
}
|
|
////////////////////////////////////////////
|
|
// group accessors /////////////////////////
|
|
////////////////////////////////////////////
|
|
|
|
bts::api::admin::BTSUserGroup *AdminServiceUtils::find_group(
|
|
bts::api::admin::AdminData &data, uint32_t id) {
|
|
for (int i = 0; i < data.user_groups_size(); i++) {
|
|
bts::api::admin::BTSUserGroup *group = data.mutable_user_groups(i);
|
|
if (id == group->id())
|
|
return group;
|
|
}
|
|
return nullptr;
|
|
}
|
|
const bts::api::admin::BTSUserGroup *const AdminServiceUtils::find_group(
|
|
const bts::api::admin::AdminData &data, uint32_t id) {
|
|
for (const bts::api::admin::BTSUserGroup &group : data.user_groups())
|
|
if (id == group.id())
|
|
return &group;
|
|
return nullptr;
|
|
}
|
|
bts::api::admin::BTSUserGroup *AdminServiceUtils::find_group(
|
|
bts::api::admin::AdminData &data, const std::string &group_name) {
|
|
for (int i = 0; i < data.user_groups_size(); i++) {
|
|
bts::api::admin::BTSUserGroup *group = data.mutable_user_groups(i);
|
|
if (group_name == group->name())
|
|
return group;
|
|
}
|
|
return nullptr;
|
|
}
|
|
uint32_t AdminServiceUtils::find_max_group_id(
|
|
const bts::api::admin::AdminData &data) {
|
|
uint32_t rv = 0;
|
|
for (const bts::api::admin::BTSUserGroup &group : data.user_groups())
|
|
if (group.id() > rv)
|
|
rv = group.id();
|
|
return rv;
|
|
}
|
|
const bts::api::admin::CMEUserData *AdminServiceUtils::get_group_cme_data(
|
|
const bts::api::admin::BTSUserGroup &group,
|
|
const bts::api::admin::AdminData &data) {
|
|
if (group.has_user_data() && group.user_data().has_exchange_user_data() &&
|
|
group.user_data().exchange_user_data().has_cme_data())
|
|
return &(group.user_data().exchange_user_data().cme_data());
|
|
else if (has_id(group.parent_group_id())) {
|
|
const bts::api::admin::BTSUserGroup *parent_group =
|
|
find_group(data, group.parent_group_id());
|
|
if (parent_group != nullptr)
|
|
return get_group_cme_data(*parent_group, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::ICEUserData *AdminServiceUtils::get_group_ice_data(
|
|
const bts::api::admin::BTSUserGroup &group,
|
|
const bts::api::admin::AdminData &data) {
|
|
if (group.has_user_data() && group.user_data().has_exchange_user_data() &&
|
|
group.user_data().exchange_user_data().has_ice_data())
|
|
return &(group.user_data().exchange_user_data().ice_data());
|
|
else if (has_id(group.parent_group_id())) {
|
|
const bts::api::admin::BTSUserGroup *parent_group =
|
|
find_group(data, group.parent_group_id());
|
|
if (parent_group != nullptr)
|
|
return get_group_ice_data(*parent_group, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::SIMUserData *AdminServiceUtils::get_group_sim_data(
|
|
const bts::api::admin::BTSUserGroup &group,
|
|
const bts::api::admin::AdminData &data) {
|
|
if (group.has_user_data() && group.user_data().has_exchange_user_data() &&
|
|
group.user_data().exchange_user_data().has_sim_data())
|
|
return &(group.user_data().exchange_user_data().sim_data());
|
|
else if (has_id(group.parent_group_id())) {
|
|
const bts::api::admin::BTSUserGroup *parent_group =
|
|
find_group(data, group.parent_group_id());
|
|
if (parent_group != nullptr)
|
|
return get_group_sim_data(*parent_group, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::UserAccountPermissions *const
|
|
AdminServiceUtils::get_group_user_permissions(
|
|
const bts::api::admin::AdminData &admin_data, uint32_t group_id) {
|
|
const bts::api::admin::BTSUserGroup *const group =
|
|
find_group(admin_data, group_id);
|
|
if (group != nullptr) {
|
|
if (group->has_user_data() &&
|
|
group->user_data().has_account_permissions())
|
|
return &group->user_data().account_permissions();
|
|
if (has_id(group->parent_group_id()))
|
|
return get_group_user_permissions(
|
|
admin_data, group->parent_group_id());
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
////////////////////////////////////////////
|
|
// group mutators //////////////////////////
|
|
////////////////////////////////////////////
|
|
bts::api::admin::BTSUserGroup *AdminServiceUtils::create_group(
|
|
bts::api::admin::AdminData &data,
|
|
uint32_t parent_group_id,
|
|
const std::string &group_name,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
// the error conditions are checked first and returned immediatly
|
|
// i. account with the name already exists
|
|
// ii. parent account is set and does not exist
|
|
result.set_is_success(true);
|
|
if (find_group(data, group_name) != nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Group by this name already exists");
|
|
return nullptr;
|
|
}
|
|
if (has_id(parent_group_id)) {
|
|
if (find_group(data, parent_group_id) == nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Parent group does not exist");
|
|
return nullptr;
|
|
}
|
|
}
|
|
uint32_t new_id = find_max_group_id(data) + 1;
|
|
bts::api::admin::BTSUserGroup *new_group_ptr = data.add_user_groups();
|
|
new_group_ptr->set_id(new_id);
|
|
new_group_ptr->set_parent_group_id(parent_group_id);
|
|
new_group_ptr->set_name(group_name);
|
|
return new_group_ptr;
|
|
}
|
|
////////////////////////////////////////////
|
|
// user accessors //////////////////////////
|
|
////////////////////////////////////////////
|
|
bts::api::admin::BTSUser *AdminServiceUtils::find_user(
|
|
bts::api::admin::AdminData &data,
|
|
const std::string &user_name,
|
|
bool include_deleted) {
|
|
auto user_ptrs = users_mutable(data, include_deleted);
|
|
for (auto user_ptr : user_ptrs) {
|
|
if (user_name == user_ptr->name())
|
|
return user_ptr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
const bts::api::admin::BTSUser *AdminServiceUtils::find_user(
|
|
const bts::api::admin::AdminData &data,
|
|
const std::string &user_name,
|
|
bool include_deleted) {
|
|
auto user_ptrs = users(data, include_deleted);
|
|
for (auto user_ptr : user_ptrs)
|
|
if (user_name == user_ptr->name())
|
|
return user_ptr;
|
|
return nullptr;
|
|
}
|
|
bts::api::admin::BTSUser *AdminServiceUtils::find_user(
|
|
bts::api::admin::AdminData &data, uint32_t id, bool include_deleted) {
|
|
auto user_ptrs = users_mutable(data, include_deleted);
|
|
for (auto user_ptr : user_ptrs) {
|
|
if (id == user_ptr->id())
|
|
return user_ptr;
|
|
}
|
|
return nullptr;
|
|
}
|
|
const bts::api::admin::BTSUser *const AdminServiceUtils::find_user(
|
|
const bts::api::admin::AdminData &data, uint32_t id, bool include_deleted) {
|
|
auto user_ptrs = users(data, include_deleted);
|
|
for (auto user_ptr : user_ptrs)
|
|
if (id == user_ptr->id())
|
|
return user_ptr;
|
|
return nullptr;
|
|
}
|
|
std::vector<const bts::api::admin::BTSUser *> AdminServiceUtils::users(
|
|
const bts::api::admin::AdminData &data, bool include_deleted) {
|
|
std::vector<const bts::api::admin::BTSUser *> rv;
|
|
for (const bts::api::admin::BTSUser &user : data.users())
|
|
if (user.is_present() || include_deleted)
|
|
rv.push_back(&user);
|
|
return rv;
|
|
}
|
|
std::vector<bts::api::admin::BTSUser *> AdminServiceUtils::users_mutable(
|
|
bts::api::admin::AdminData &data, bool include_deleted) {
|
|
std::vector<bts::api::admin::BTSUser *> rv;
|
|
for (int i = 0; i < data.users_size(); i++) {
|
|
auto user_ptr = data.mutable_users(i);
|
|
if (user_ptr->is_present() || include_deleted)
|
|
rv.push_back(user_ptr);
|
|
}
|
|
return rv;
|
|
}
|
|
uint32_t AdminServiceUtils::find_max_user_id(
|
|
const bts::api::admin::AdminData &data) {
|
|
uint32_t rv = 0;
|
|
auto user_ptrs = users(data, true);
|
|
for (auto user_ptr : user_ptrs)
|
|
if (user_ptr->id() > rv)
|
|
rv = user_ptr->id();
|
|
return rv;
|
|
}
|
|
|
|
const bts::api::admin::CMEUserData *AdminServiceUtils::get_user_cme_data(
|
|
const bts::api::admin::BTSUser &user,
|
|
const bts::api::admin::AdminData &data) {
|
|
if (user.has_user_data() && user.user_data().has_exchange_user_data() &&
|
|
user.user_data().exchange_user_data().has_cme_data())
|
|
return &(user.user_data().exchange_user_data().cme_data());
|
|
else {
|
|
const bts::api::admin::BTSUserGroup *parent_group =
|
|
find_group(data, user.parent_group_id());
|
|
if (parent_group != nullptr)
|
|
return get_group_cme_data(*parent_group, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::ICEUserData *AdminServiceUtils::get_user_ice_data(
|
|
const bts::api::admin::BTSUser &user,
|
|
const bts::api::admin::AdminData &data) {
|
|
if (user.has_user_data() && user.user_data().has_exchange_user_data() &&
|
|
user.user_data().exchange_user_data().has_ice_data())
|
|
return &(user.user_data().exchange_user_data().ice_data());
|
|
else {
|
|
const bts::api::admin::BTSUserGroup *parent_group =
|
|
find_group(data, user.parent_group_id());
|
|
if (parent_group != nullptr)
|
|
return get_group_ice_data(*parent_group, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const bts::api::admin::SIMUserData *AdminServiceUtils::get_user_sim_data(
|
|
const bts::api::admin::BTSUser &user,
|
|
const bts::api::admin::AdminData &data) {
|
|
if (user.has_user_data() && user.user_data().has_exchange_user_data() &&
|
|
user.user_data().exchange_user_data().has_sim_data())
|
|
return &(user.user_data().exchange_user_data().sim_data());
|
|
else {
|
|
const bts::api::admin::BTSUserGroup *parent_group =
|
|
find_group(data, user.parent_group_id());
|
|
if (parent_group != nullptr)
|
|
return get_group_sim_data(*parent_group, data);
|
|
}
|
|
return nullptr;
|
|
}
|
|
// finds the "exchange user" (ex: "operator_id" at CME or "authorized_trader"
|
|
// at ICE) for a user
|
|
std::string AdminServiceUtils::find_user_exchange_id(
|
|
const bts::api::admin::AdminData &data,
|
|
const bts::api::admin::BTSUser &user,
|
|
api::Venue exchange,
|
|
bts::api::admin::AdminServiceOperationResult &out_result) {
|
|
out_result.set_is_success(true);
|
|
std::string rv = "";
|
|
switch (exchange) {
|
|
case api::Venue::VENUE_GLBX: {
|
|
auto cme_user_data = get_user_cme_data(user, data);
|
|
if (cme_user_data != nullptr)
|
|
rv = cme_user_data->operator_id();
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_ICE: {
|
|
auto ice_user_data = get_user_ice_data(user, data);
|
|
if (ice_user_data != nullptr)
|
|
rv = ice_user_data->operator_id();
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_SIM:
|
|
case api::Venue::VENUE_SIMICE: {
|
|
auto sim_user_data = get_user_sim_data(user, data);
|
|
if (sim_user_data != nullptr)
|
|
rv = sim_user_data->operator_id();
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_DERIBIT: // TODO
|
|
case api::Venue::VENUE_FTX: // TODO
|
|
case api::Venue::VENUE_BINANCE: // TODO
|
|
case api::Venue::VENUE_BINANCE_COIN_FUTURES:
|
|
case api::Venue::VENUE_BINANCE_US:
|
|
case api::Venue::VENUE_COINBASE:
|
|
case api::Venue::VENUE_BINANCE_USDS_FUTURES:
|
|
case api::Venue::VENUE_OKX:
|
|
case api::Venue::VENUE_UNSET:
|
|
case api::Venue::VENUE_BTS:
|
|
case api::Venue::VENUE_CBOE:
|
|
case api::Venue::VENUE_TAIFEX:
|
|
case api::Venue::VENUE_CBOECFE:
|
|
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
|
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Exchange not supported");
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
std::string AdminServiceUtils::find_user_company_id(
|
|
const bts::api::admin::AdminData &data,
|
|
const bts::api::admin::BTSUser &user,
|
|
api::Venue exchange,
|
|
bts::api::admin::AdminServiceOperationResult &out_result) {
|
|
out_result.set_is_success(true);
|
|
std::string rv = "";
|
|
switch (exchange) {
|
|
case api::Venue::VENUE_ICE: {
|
|
auto ice_user_data = get_user_ice_data(user, data);
|
|
if (ice_user_data != nullptr)
|
|
rv = std::to_string(ice_user_data->company_id());
|
|
break;
|
|
}
|
|
case api::Venue::VENUE_DERIBIT:
|
|
case api::Venue::VENUE_FTX: // TODO
|
|
case api::Venue::VENUE_BINANCE: // TODO
|
|
case api::Venue::VENUE_BINANCE_COIN_FUTURES:
|
|
case api::Venue::VENUE_BINANCE_US:
|
|
case api::Venue::VENUE_COINBASE:
|
|
case api::Venue::VENUE_BINANCE_USDS_FUTURES:
|
|
case api::Venue::VENUE_OKX:
|
|
case api::Venue::VENUE_SIM:
|
|
case api::Venue::VENUE_SIMICE:
|
|
case api::Venue::VENUE_GLBX:
|
|
case api::Venue::VENUE_UNSET:
|
|
case api::Venue::VENUE_BTS:
|
|
case api::Venue::VENUE_CBOE:
|
|
case api::Venue::VENUE_TAIFEX:
|
|
|
|
case api::Venue::VENUE_CBOECFE:
|
|
case api::Venue::Venue_INT_MIN_SENTINEL_DO_NOT_USE_:
|
|
case api::Venue::Venue_INT_MAX_SENTINEL_DO_NOT_USE_:
|
|
out_result.set_is_success(false);
|
|
out_result.set_error_text("Exchange not supported");
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
std::pair<const BTSAccount *, const BTSUser *>
|
|
AdminServiceUtils::find_user_account_matches(
|
|
const AdminData &admin_data,
|
|
const std::string &connection,
|
|
const std::string &exchange_account,
|
|
const std::string &exchange_user,
|
|
api::Venue exchange) {
|
|
AdminServiceOperationResult find_account_result, find_user_result;
|
|
// i. uses the exchange and exchange_user to reverse lookup the user(s)
|
|
auto user_ptrs = users(admin_data, false);
|
|
std::vector<BTSUser const *> matching_users;
|
|
for (BTSUser const *u : user_ptrs) {
|
|
auto exchange_u =
|
|
find_user_exchange_id(admin_data, *u, exchange, find_user_result);
|
|
if (find_user_result.is_success() &&
|
|
boost::algorithm::iequals(exchange_u, exchange_user))
|
|
matching_users.push_back(u);
|
|
}
|
|
// i.5
|
|
// At the ice, they send back the login level tag50 in exec reports which
|
|
// doesn't match any user level tag50s in the exchange_user so instead we
|
|
// look for the CompanyID (or client_id, tag 109) field here. If this field
|
|
// matches we have a good bet that the user we find is enough to fulfill the
|
|
// routing record enough to cancel or modify orphaned orders, etc
|
|
for (BTSUser const *u : user_ptrs) {
|
|
auto exchange_u =
|
|
find_user_company_id(admin_data, *u, exchange, find_user_result);
|
|
if (find_user_result.is_success() &&
|
|
boost::algorithm::iequals(exchange_u, exchange_user))
|
|
matching_users.push_back(u);
|
|
}
|
|
// ii. uses the exchange, connection and exchange_account to reverse lookup
|
|
// the account(s)
|
|
auto account_ptrs = accounts(admin_data, false);
|
|
std::vector<BTSAccount const *> matching_accounts;
|
|
for (BTSAccount const *a : account_ptrs)
|
|
if (account_has_connection(*a, connection)) {
|
|
auto exchange_a = find_account_exchange_account(
|
|
admin_data, *a, exchange, find_account_result);
|
|
if (find_account_result.is_success() &&
|
|
boost::algorithm::iequals(exchange_a, exchange_account))
|
|
matching_accounts.push_back(a);
|
|
}
|
|
// iii. finds the first account from ii that the user from i is authorized to
|
|
// trade
|
|
for (BTSUser const *u : matching_users) {
|
|
std::vector<BTSAccount const *> user_auth_accounts;
|
|
find_user_trading_accounts(admin_data, u->id(), user_auth_accounts);
|
|
for (BTSAccount const *i : user_auth_accounts)
|
|
for (BTSAccount const *j : matching_accounts)
|
|
if (i->id() == j->id())
|
|
return std::pair<BTSAccount const *, BTSUser const *>(i, u);
|
|
}
|
|
return std::pair<const BTSAccount *, const BTSUser *>(nullptr, nullptr);
|
|
}
|
|
|
|
// for a given user finds the account permissions (if permissions are
|
|
// derived from the group, it traverses the group hierarcy to find the
|
|
// correct permissions.
|
|
const bts::api::admin::UserAccountPermissions *
|
|
AdminServiceUtils::get_user_permissions(
|
|
const bts::api::admin::AdminData &admin_data, uint32_t user_id) {
|
|
const bts::api::admin::BTSUser *const user = find_user(admin_data, user_id);
|
|
if (user != nullptr) {
|
|
if (user->has_user_data() && user->user_data().has_account_permissions())
|
|
return &user->user_data().account_permissions();
|
|
else
|
|
return get_group_user_permissions(admin_data, user->parent_group_id());
|
|
}
|
|
return nullptr;
|
|
}
|
|
// for a given user, fills in the associated_accounts ref arg
|
|
// with the accounts the user has permission to trade in
|
|
void AdminServiceUtils::find_user_trading_accounts(
|
|
const bts::api::admin::AdminData &admin_data,
|
|
uint32_t user_id,
|
|
std::vector<const api::admin::BTSAccount *> &associated_accounts) {
|
|
const bts::api::admin::UserAccountPermissions *user_perm_ptr =
|
|
get_user_permissions(admin_data, user_id);
|
|
if (user_perm_ptr != nullptr)
|
|
for (auto it = user_perm_ptr->account_permissions().begin();
|
|
it != user_perm_ptr->account_permissions().end(); it++)
|
|
if (it->second.has_trading_permission() &&
|
|
it->second.trading_permission().has_permissions()) {
|
|
const api::admin::BTSAccount *account_ptr =
|
|
find_account(admin_data, it->first);
|
|
if (account_ptr != nullptr)
|
|
associated_accounts.push_back(account_ptr);
|
|
}
|
|
}
|
|
|
|
// for a given account, fills in the associated_users ref arg
|
|
// with the users that can trade into the account
|
|
void AdminServiceUtils::find_users_for_trading_account(
|
|
const AdminData &admin_data,
|
|
uint32_t account_id,
|
|
std::vector<const BTSUser *> &associated_users) {
|
|
for (const auto &u : AdminServiceUtils::users(admin_data, false)) {
|
|
const auto user_perm_ptr = get_user_permissions(admin_data, u->id());
|
|
if (user_perm_ptr) {
|
|
const auto &permission_unit =
|
|
user_perm_ptr->account_permissions().find(account_id);
|
|
if (permission_unit != user_perm_ptr->account_permissions().end() &&
|
|
permission_unit->second.has_trading_permission() &&
|
|
permission_unit->second.trading_permission().has_permissions()) {
|
|
associated_users.push_back(u);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AdminServiceUtils::validate_user_update(
|
|
const bts::api::admin::AdminData &admin_data,
|
|
const bts::api::admin::BTSUser &updated_user,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
result.set_is_success(true);
|
|
// validate id
|
|
if (find_user(admin_data, updated_user.id()) == nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Could not find user id");
|
|
return;
|
|
}
|
|
// validate that name change doesnt collide
|
|
auto user_ptrs = users(admin_data, true);
|
|
for (auto user_ptr : user_ptrs)
|
|
if (user_ptr->id() != updated_user.id() &&
|
|
user_ptr->name() == updated_user.name()) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("User by this name already exists");
|
|
return;
|
|
}
|
|
validate_user_exchange_data(updated_user, result);
|
|
}
|
|
void AdminServiceUtils::validate_user_exchange_data(
|
|
const bts::api::admin::BTSUser &user,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
result.set_is_success(true);
|
|
// this is not right (should navigate to the group)
|
|
if (user.has_user_data() && user.user_data().has_exchange_user_data() &&
|
|
user.user_data().exchange_user_data().has_cme_data()) {
|
|
const api::admin::CMEUserData &cme_user_data =
|
|
user.user_data().exchange_user_data().cme_data();
|
|
if (cme_user_data.operator_id().size() > 18) {
|
|
result.set_is_success(false);
|
|
result.set_error_text(
|
|
"CME operator id can not be more 12 characters long");
|
|
}
|
|
}
|
|
}
|
|
void AdminServiceUtils::get_md_entitlement_report(
|
|
const AdminData &admin_data,
|
|
std::vector<MDEntitlementReportUnit> &entitlements) {
|
|
for (const auto &user : admin_data.users()) {
|
|
const CMEUserData *cme_data =
|
|
AdminServiceUtils::get_user_cme_data(user, admin_data);
|
|
if (cme_data != nullptr) {
|
|
for (const auto &cme_mic_data : cme_data->md_permissions()) {
|
|
MDEntitlementReportUnit rv =
|
|
get_cme_md_entitlement_unit(user, cme_mic_data);
|
|
entitlements.push_back(rv);
|
|
}
|
|
}
|
|
const ICEUserData *ice_data =
|
|
AdminServiceUtils::get_user_ice_data(user, admin_data);
|
|
if (ice_data != nullptr) {
|
|
for (const auto &ice_mic_data : ice_data->md_permissions()) {
|
|
MDEntitlementReportUnit rv =
|
|
get_ice_md_entitlement_unit(user, ice_mic_data);
|
|
entitlements.push_back(rv);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
MDEntitlementReportUnit AdminServiceUtils::get_cme_md_entitlement_unit(
|
|
const BTSUser &user, const CMEMicData &cme_mic_data) {
|
|
MDEntitlementReportUnit rv;
|
|
rv.set_user(user.name());
|
|
rv.set_user_id(user.id());
|
|
rv.set_exchange("GLBX");
|
|
switch (cme_mic_data.mic()) {
|
|
case api::CMEMics::CME:
|
|
rv.set_mic("CME");
|
|
break;
|
|
case api::CMEMics::NYMEX:
|
|
rv.set_mic("NYMEX");
|
|
break;
|
|
case api::CMEMics::CBT:
|
|
rv.set_mic("CBT");
|
|
break;
|
|
case api::CMEMics::COMEX:
|
|
rv.set_mic("COMEX");
|
|
break;
|
|
case api::CMEMics::MGE:
|
|
rv.set_mic("MGE");
|
|
break;
|
|
case api::CMEMics::DME:
|
|
rv.set_mic("DME");
|
|
break;
|
|
case api::CMEMics::NYMSW:
|
|
rv.set_mic("NYMSW");
|
|
break;
|
|
case api::CMEMics::FXS:
|
|
rv.set_mic("FXS");
|
|
break;
|
|
case api::CMEMics::UNSET:
|
|
case api::CMEMics::CMEMics_INT_MIN_SENTINEL_DO_NOT_USE_:
|
|
case api::CMEMics::CMEMics_INT_MAX_SENTINEL_DO_NOT_USE_:
|
|
rv.set_mic("");
|
|
break;
|
|
}
|
|
rv.set_enabled(cme_mic_data.enabled());
|
|
std::ostringstream key;
|
|
key << rv.user() << rv.exchange() << rv.mic();
|
|
rv.set_record_id(key.str());
|
|
return rv;
|
|
}
|
|
MDEntitlementReportUnit AdminServiceUtils::get_ice_md_entitlement_unit(
|
|
const BTSUser &user, const ICEMicData &ice_mic_data) {
|
|
MDEntitlementReportUnit rv;
|
|
rv.set_user(user.name());
|
|
rv.set_user_id(user.id());
|
|
rv.set_exchange(bts::api::Venue_Name(bts::api::Venue::VENUE_ICE));
|
|
rv.set_mic(bts::api::ICEMics_Name(ice_mic_data.mic()));
|
|
|
|
rv.set_enabled(ice_mic_data.enabled());
|
|
std::ostringstream key;
|
|
key << rv.user() << rv.exchange() << rv.mic();
|
|
rv.set_record_id(key.str());
|
|
return rv;
|
|
}
|
|
|
|
void AdminServiceUtils::get_user_symbol_permissions(
|
|
const AdminData &data,
|
|
const BTSUser &user,
|
|
std::vector<UserSymbolMDPermissionUnit> &rv) {
|
|
std::map<api::CMEMics, bool> mic_perm_map;
|
|
auto exchange = api::Venue::VENUE_GLBX;
|
|
const CMEUserData *cme_data = get_user_cme_data(user, data);
|
|
if (cme_data != nullptr)
|
|
for (const auto &mic_data : cme_data->md_permissions())
|
|
if (mic_data.enabled())
|
|
mic_perm_map[mic_data.mic()] = true;
|
|
const auto &cme_symb_mics = config::get<config::CmeSymbolMics>().cme_mic();
|
|
for (auto it = cme_symb_mics.begin(); it != cme_symb_mics.end(); it++) {
|
|
const std::string &symbol = it->first;
|
|
api::CMEMics mic = it->second;
|
|
UserSymbolMDPermissionUnit u;
|
|
std::ostringstream key;
|
|
key << exchange << user.name() << symbol;
|
|
u.set_record_id(key.str());
|
|
u.set_user_id(user.id());
|
|
u.set_exchange(exchange);
|
|
u.set_symbol(symbol);
|
|
u.set_enabled(mic_perm_map.find(mic) != mic_perm_map.end());
|
|
rv.push_back(u);
|
|
}
|
|
}
|
|
////////////////////////////////////////////
|
|
// user mutators ///////////////////////////
|
|
////////////////////////////////////////////
|
|
bts::api::admin::BTSUser *AdminServiceUtils::create_user(
|
|
bts::api::admin::AdminData &data,
|
|
uint32_t parent_group_id,
|
|
const std::string &name,
|
|
const std::string &password,
|
|
const std::string &full_name,
|
|
const std::string &company,
|
|
bool is_active,
|
|
const bts::api::admin::LicenseData &license_data,
|
|
const bts::api::admin::LicenseEntitlements &license_entitlements,
|
|
bts::api::admin::AdminServiceCreateEntityResult &result) {
|
|
result.set_is_success(true);
|
|
// the error conditions are checked first and returned immediatly
|
|
// i. user with the name already exists
|
|
// ii. parent group does not exist
|
|
if (find_user(data, name, true) != nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("User by this name already exists");
|
|
return nullptr;
|
|
}
|
|
if (find_group(data, parent_group_id) == nullptr) {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Parent group does not exist");
|
|
return nullptr;
|
|
}
|
|
uint32_t new_id = AdminServiceUtils::find_max_user_id(data) + 1;
|
|
bts::api::admin::BTSUser *new_user_ptr = data.add_users();
|
|
new_user_ptr->set_is_present(true);
|
|
new_user_ptr->set_id(new_id);
|
|
new_user_ptr->set_parent_group_id(parent_group_id);
|
|
new_user_ptr->set_name(name);
|
|
new_user_ptr->set_password(password);
|
|
new_user_ptr->set_full_name(full_name);
|
|
new_user_ptr->set_company(company);
|
|
new_user_ptr->set_is_active(is_active);
|
|
new_user_ptr->mutable_license_data()->CopyFrom(license_data);
|
|
new_user_ptr->mutable_license_entitlements()->CopyFrom(license_entitlements);
|
|
result.set_new_id(new_id);
|
|
return new_user_ptr;
|
|
}
|
|
void AdminServiceUtils::set_user_exchange_data(
|
|
bts::api::admin::BTSUser *user,
|
|
const bts::api::admin::ExchangeUserData &exchange_user_data) {
|
|
if (!user->has_user_data())
|
|
user->mutable_user_data();
|
|
if (!user->user_data().has_exchange_user_data())
|
|
user->mutable_user_data()->mutable_exchange_user_data()->CopyFrom(
|
|
exchange_user_data);
|
|
}
|
|
// void
|
|
// AdminServiceUtils::set_user_md_entitlement_data(bts::api::admin::BTSUser*
|
|
// user,
|
|
// const
|
|
// bts::api::admin::ExchangeUserMarketDataEntitlementData&
|
|
// exchange_user_md_entitelemnt_data){
|
|
// if (!user->has_user_data())
|
|
// user->mutable_user_data();
|
|
// if (!user->user_data().has_exchange_md_entitlement_data())
|
|
// user->mutable_user_data()->mutable_exchange_md_entitlement_data()->CopyFrom(exchange_user_md_entitelemnt_data);
|
|
// }
|
|
void AdminServiceUtils::clear_user_accounts(bts::api::admin::BTSUser *user) {
|
|
if (user->has_user_data() && user->user_data().has_account_permissions())
|
|
user->mutable_user_data()->clear_account_permissions();
|
|
}
|
|
void AdminServiceUtils::set_user_accounts(
|
|
bts::api::admin::BTSUser *user,
|
|
const bts::api::admin::UserAccountPermissions &user_account_permissions) {
|
|
if (!user->has_user_data())
|
|
user->mutable_user_data();
|
|
user->mutable_user_data()->mutable_account_permissions()->CopyFrom(
|
|
user_account_permissions);
|
|
}
|
|
bts::api::admin::BTSUser *AdminServiceUtils::update_user(
|
|
bts::api::admin::AdminData &admin_data,
|
|
const bts::api::admin::BTSUser &updated_user,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
validate_user_update(admin_data, updated_user, result);
|
|
if (result.is_success()) {
|
|
bts::api::admin::BTSUser *user_ptr =
|
|
find_user(admin_data, updated_user.id());
|
|
user_ptr->CopyFrom(updated_user);
|
|
return user_ptr;
|
|
} else
|
|
return nullptr;
|
|
}
|
|
void AdminServiceUtils::delete_user(
|
|
bts::api::admin::AdminData &admin_data,
|
|
const bts::api::admin::IDAPIArgument &id,
|
|
bts::api::admin::AdminServiceOperationResult &result) {
|
|
result.set_is_success(true);
|
|
api::admin::BTSUser *user_ptr =
|
|
AdminServiceUtils::find_user(admin_data, id.id());
|
|
if (user_ptr != nullptr) {
|
|
std::string deleted_name;
|
|
int deleted_idx = 0;
|
|
do {
|
|
// keep going until the modified name is not found,
|
|
// otherwise keep "incrementing" the modified name
|
|
deleted_idx++;
|
|
deleted_name =
|
|
deleted_idx == 1
|
|
? fmt::format("DELETED_{}", user_ptr->name())
|
|
: fmt::format("DELETED_{}_{}", deleted_idx, user_ptr->name());
|
|
} while (AdminServiceUtils::find_user(admin_data, deleted_name, true) !=
|
|
nullptr);
|
|
user_ptr->set_is_present(false);
|
|
user_ptr->set_name(deleted_name);
|
|
} else {
|
|
result.set_is_success(false);
|
|
result.set_error_text("Could not find user");
|
|
}
|
|
}
|
|
////////////////////////////////////////////
|
|
// risk limits //////////////////////////////
|
|
////////////////////////////////////////////
|
|
bool AdminServiceUtils::_sort_security_scopes(
|
|
const bts::api::admin::SecurityScope &a,
|
|
const bts::api::admin::SecurityScope &b) {
|
|
// for both the sec and product scope sorting, the more
|
|
// qualified arg is sent to the top (vs wildcard). the
|
|
// order of qualification is sec_id, symbol, type, exchange.
|
|
// if both a and b are equally qualified, it is a
|
|
// a dont-care case (in terms of sec/prod res) and
|
|
// ascending orderring is used
|
|
if (has_id(a.security_id())) {
|
|
if (has_id(b.security_id()))
|
|
return a.security_id() < b.security_id();
|
|
else
|
|
return true;
|
|
}
|
|
if (has_id(b.security_id()))
|
|
return false;
|
|
// symbol
|
|
if (is_symbol_set(a.security_symbol())) {
|
|
if (is_symbol_set(b.security_symbol()))
|
|
return a.security_symbol() < b.security_symbol();
|
|
else
|
|
return true;
|
|
}
|
|
if (is_symbol_set(b.security_symbol()))
|
|
return false;
|
|
// sec type
|
|
if (a.security_type() != b.security_type())
|
|
return a.security_type() < b.security_type();
|
|
return a.exchange() < b.exchange();
|
|
}
|
|
bool AdminServiceUtils::_sort_product_scopes(
|
|
const bts::api::admin::ProductScope &a,
|
|
const bts::api::admin::ProductScope &b) {
|
|
// symbol
|
|
if (is_symbol_set(a.security_symbol())) {
|
|
if (is_symbol_set(b.security_symbol()))
|
|
return a.security_symbol() < b.security_symbol();
|
|
else
|
|
return true;
|
|
}
|
|
if (is_symbol_set(b.security_symbol()))
|
|
return false;
|
|
// sec type
|
|
if (a.security_type() != b.security_type())
|
|
return a.security_type() < b.security_type();
|
|
return a.exchange() < b.exchange();
|
|
}
|
|
void AdminServiceUtils::sort_limits(bts::api::admin::BTSAccount &account) {
|
|
std::sort(
|
|
account.mutable_security_position_limits()->begin(),
|
|
account.mutable_security_position_limits()->end(),
|
|
[](const bts::api::admin::AccountSecurityPositionLimitUnit &a,
|
|
const bts::api::admin::AccountSecurityPositionLimitUnit &b) {
|
|
return _sort_security_scopes(a.security(), b.security());
|
|
});
|
|
std::sort(
|
|
account.mutable_product_position_limits()->begin(),
|
|
account.mutable_product_position_limits()->end(),
|
|
[](const bts::api::admin::AccountProductPositionLimitUnit &a,
|
|
const bts::api::admin::AccountProductPositionLimitUnit &b) {
|
|
return _sort_product_scopes(a.product(), b.product());
|
|
});
|
|
if (account.has_security_clip_limits())
|
|
std::sort(
|
|
account.mutable_security_clip_limits()->mutable_limit()->begin(),
|
|
account.mutable_security_clip_limits()->mutable_limit()->end(),
|
|
[](const bts::api::admin::AccountSecurityClipLimitUnit &a,
|
|
const bts::api::admin::AccountSecurityClipLimitUnit &b) {
|
|
return _sort_security_scopes(a.security(), b.security());
|
|
});
|
|
}
|
|
bts::api::admin::AdminData AdminServiceUtils::sort_limits(
|
|
const bts::api::admin::AdminData &admin_data) {
|
|
bts::api::admin::AdminData rv;
|
|
rv.CopyFrom(admin_data);
|
|
for (int i = 0; i < rv.accounts_size(); i++)
|
|
sort_limits(*rv.mutable_accounts(i));
|
|
return rv;
|
|
}
|
|
// find the clip size for a security, account
|
|
const uint32_t AdminServiceUtils::find_account_security_clip_size(
|
|
const bts::api::admin::BTSAccount &account, const api::Security &security) {
|
|
uint32_t rv = 0;
|
|
if (account.has_security_clip_limits())
|
|
for (const auto &limit : account.security_clip_limits().limit()) {
|
|
if (match_security_scope(limit.security(), security))
|
|
return limit.clip_size();
|
|
}
|
|
return rv;
|
|
}
|
|
// find the position limit for an account, security
|
|
const bts::api::admin::AccountSecurityPositionLimitUnit *
|
|
AdminServiceUtils::find_account_security_position_limit(
|
|
const bts::api::admin::BTSAccount &account, const api::Security &security) {
|
|
for (const auto &limit : account.security_position_limits())
|
|
if (match_security_scope(limit.security(), security))
|
|
return &limit;
|
|
return nullptr;
|
|
}
|
|
// find the position limit for an account, product
|
|
const bts::api::admin::AccountProductPositionLimitUnit *
|
|
AdminServiceUtils::find_account_product_position_limit(
|
|
const bts::api::admin::BTSAccount &account, const api::Product &product) {
|
|
for (const auto &limit : account.product_position_limits())
|
|
if (match_product_scope(limit.product(), product))
|
|
return &limit;
|
|
return nullptr;
|
|
}
|
|
bool AdminServiceUtils::match_security_scope(
|
|
const bts::api::admin::SecurityScope &scope,
|
|
const bts::api::Security &security) {
|
|
if (has_id(scope.security_id())) {
|
|
if (scope.security_id() == security.id())
|
|
return true;
|
|
} else if (
|
|
security.exchange() == scope.exchange() &&
|
|
security_type(security) == scope.security_type() &&
|
|
_match_limit_rule_symbol(security.symbol(), scope.security_symbol()))
|
|
return true;
|
|
return false;
|
|
}
|
|
bool AdminServiceUtils::match_product_scope(
|
|
const bts::api::admin::ProductScope &scope,
|
|
const bts::api::Product &product) {
|
|
return product.exchange() == scope.exchange() &&
|
|
product.type() == scope.security_type() &&
|
|
_match_limit_rule_symbol(product.symbol(), scope.security_symbol());
|
|
}
|
|
bool AdminServiceUtils::match_product(
|
|
const api::Security &security, const api::Product &product) {
|
|
return product.exchange() == security.exchange() &&
|
|
product.type() == security_type(security) &&
|
|
product.symbol() == security.symbol();
|
|
}
|
|
bool AdminServiceUtils::_match_limit_rule_symbol(
|
|
const std::string &symbol, const std::string &limit_symbol) {
|
|
return limit_symbol == "*" || symbol == limit_symbol;
|
|
}
|
|
api::SecurityType AdminServiceUtils::security_type(
|
|
const api::Security &security) {
|
|
switch (security.Contract_case()) {
|
|
case api::Security::ContractCase::kFuture:
|
|
return api::SecurityType::SECURITYTYPE_FUTURE;
|
|
case api::Security::ContractCase::kOption:
|
|
return api::SecurityType::SECURITYTYPE_OPTION;
|
|
case api::Security::ContractCase::kSpot:
|
|
return api::SecurityType::SECURITYTYPE_SPOT;
|
|
case api::Security::ContractCase::kSpread:
|
|
return api::SecurityType::SECURITYTYPE_SPREAD;
|
|
case api::Security::ContractCase::kSynthetic:
|
|
return api::SecurityType::SECURITYTYPE_SYNTHETIC;
|
|
case api::Security::ContractCase::CONTRACT_NOT_SET:
|
|
return api::SecurityType::SECURITYTYPE_UNSET;
|
|
}
|
|
return api::SecurityType::SECURITYTYPE_UNSET;
|
|
}
|
|
////////////////////////////////////////////
|
|
// boostrapping ////////////////////////////
|
|
////////////////////////////////////////////
|
|
|
|
void add_product_position_limits(
|
|
bts::api::admin::BTSAccount *to_account,
|
|
api::Venue venue,
|
|
api::SecurityType sec_type,
|
|
uint32_t limit) {
|
|
LOG(OrderMan, Info,
|
|
"Adding position limits. account: {}; venue: {}; type: {}",
|
|
to_account->name(), Venue_Name(venue), SecurityType_Name(sec_type));
|
|
const auto filter = SecurityCriteria::create(
|
|
venue == Venue::VENUE_UNSET
|
|
? vector<api::domain::Venue>{}
|
|
: vector<api::domain::Venue>{DomainSecurityUtils::convert(venue)},
|
|
{DomainSecurityUtils::convert(sec_type)});
|
|
const auto symbols = SymbolLoader::load(filter);
|
|
|
|
for (auto const &s : symbols) {
|
|
auto acct_a_prod_limit = to_account->add_product_position_limits();
|
|
acct_a_prod_limit->mutable_product()->set_exchange(s.exchange());
|
|
acct_a_prod_limit->mutable_product()->set_security_type(s.type());
|
|
acct_a_prod_limit->mutable_product()->set_security_symbol(s.symbol());
|
|
acct_a_prod_limit->set_long_position_limit(limit);
|
|
acct_a_prod_limit->set_short_position_limit(limit);
|
|
}
|
|
}
|
|
|
|
void add_security_clip_sizes_to_account(
|
|
bts::api::admin::BTSAccount *to_account,
|
|
api::Venue venue,
|
|
api::SecurityType sec_type,
|
|
uint32_t limit) {
|
|
LOG(OrderMan, Info,
|
|
"Adding sec clip size limit. account: {}; venue {}; type {}",
|
|
to_account->name(), Venue_Name(venue), SecurityType_Name(sec_type));
|
|
const auto filter = bts::domain::SecurityCriteria::create(
|
|
{DomainSecurityUtils::convert(venue)},
|
|
{DomainSecurityUtils::convert(sec_type)});
|
|
const auto symbols = SymbolLoader::load(filter);
|
|
|
|
for (auto const &s : symbols) {
|
|
auto acct_a_clip_size =
|
|
to_account->mutable_security_clip_limits()->add_limit();
|
|
acct_a_clip_size->mutable_security()->set_exchange(s.exchange());
|
|
acct_a_clip_size->mutable_security()->set_security_type(s.type());
|
|
acct_a_clip_size->mutable_security()->set_security_symbol(s.symbol());
|
|
acct_a_clip_size->set_clip_size(limit);
|
|
}
|
|
}
|
|
|
|
void add_security_position_limits(
|
|
bts::api::admin::BTSAccount *to_account,
|
|
api::Venue venue,
|
|
api::SecurityType sec_type) {
|
|
auto acct_a1_sec_limit = to_account->add_security_position_limits();
|
|
acct_a1_sec_limit->mutable_security()->set_exchange(venue);
|
|
acct_a1_sec_limit->mutable_security()->set_security_type(sec_type);
|
|
acct_a1_sec_limit->mutable_security()->set_security_symbol("*");
|
|
acct_a1_sec_limit->set_long_position_limit(10000);
|
|
acct_a1_sec_limit->set_short_position_limit(10000);
|
|
}
|
|
|
|
void AdminServiceUtils::bootstrap_data(bts::api::admin::AdminData &data) {
|
|
data.set_id(1);
|
|
bts::api::admin::AdminServiceOperationResult result;
|
|
bts::api::admin::AdminServiceCreateAccountResult account_result;
|
|
bts::api::admin::AdminServiceCreateEntityResult user_result;
|
|
// adding accounts
|
|
auto parent_account = create_account(
|
|
data, 0, std::string("ACC A"), std::string("description"), true,
|
|
account_result);
|
|
auto account_1 = create_account(
|
|
data, parent_account->id(), std::string("ACC A1"),
|
|
std::string("description"), true, account_result);
|
|
account_1->set_is_active(true);
|
|
auto account_2 = create_account(
|
|
data, parent_account->id(), std::string("ACC A2"),
|
|
std::string("description"), true, account_result);
|
|
account_2->set_is_active(true);
|
|
auto account_3 = create_account(
|
|
data, parent_account->id(), std::string("ACC A3"),
|
|
std::string("description"), true, account_result);
|
|
account_3->set_is_active(true);
|
|
auto account_4 = create_account(
|
|
data, parent_account->id(), std::string("BLUETST"),
|
|
std::string("description"), true, account_result);
|
|
account_4->set_is_active(true);
|
|
// BTC, ETH accounts
|
|
auto account_btc = create_account(
|
|
data, parent_account->id(), std::string("ACC_BTC"),
|
|
std::string("description"), true, account_result);
|
|
account_btc->set_is_active(true);
|
|
auto account_eth = create_account(
|
|
data, parent_account->id(), std::string("ACC_ETH"),
|
|
std::string("description"), true, account_result);
|
|
account_eth->set_is_active(true);
|
|
//
|
|
create_account(
|
|
data, parent_account->id(), std::string("ACC A4"),
|
|
std::string("description"), true, account_result);
|
|
// add group
|
|
auto def_group = create_group(data, 0, std::string("default"), result);
|
|
// adding users to the group
|
|
bts::api::admin::LicenseData license_data;
|
|
bts::api::admin::LicenseEntitlements license_entitlements;
|
|
std::string empty("");
|
|
auto user_1 = create_user(
|
|
data, def_group->id(), std::string("bts"), std::string(""), empty, empty,
|
|
false, license_data, license_entitlements, user_result);
|
|
user_1->set_is_active(true);
|
|
auto user_2 = create_user(
|
|
data, def_group->id(), std::string("bts_2"), std::string("bts_2"), empty,
|
|
empty, false, license_data, license_entitlements, user_result);
|
|
user_2->set_is_active(true);
|
|
auto user_3 = create_user(
|
|
data, def_group->id(), std::string("bts_3"), std::string("bts_3"), empty,
|
|
empty, false, license_data, license_entitlements, user_result);
|
|
user_3->set_is_active(true);
|
|
// associate users
|
|
bts::api::admin::UserAccountPermissionUnit permission_unit;
|
|
permission_unit.mutable_trading_permission()->set_has_permissions(true);
|
|
permission_unit.mutable_admin_permission()->set_has_permissions(true);
|
|
bts::api::admin::UserAccountPermissions account_permissions;
|
|
account_permissions.mutable_account_permissions()->insert(
|
|
google::protobuf::MapPair<
|
|
uint32_t, bts::api::admin::UserAccountPermissionUnit>(
|
|
parent_account->id(), permission_unit));
|
|
account_permissions.mutable_account_permissions()->insert(
|
|
google::protobuf::MapPair<
|
|
uint32_t, bts::api::admin::UserAccountPermissionUnit>(
|
|
account_1->id(), permission_unit));
|
|
account_permissions.mutable_account_permissions()->insert(
|
|
google::protobuf::MapPair<
|
|
uint32_t, bts::api::admin::UserAccountPermissionUnit>(
|
|
account_2->id(), permission_unit));
|
|
account_permissions.mutable_account_permissions()->insert(
|
|
google::protobuf::MapPair<
|
|
uint32_t, bts::api::admin::UserAccountPermissionUnit>(
|
|
account_3->id(), permission_unit));
|
|
account_permissions.mutable_account_permissions()->insert(
|
|
google::protobuf::MapPair<
|
|
uint32_t, bts::api::admin::UserAccountPermissionUnit>(
|
|
account_4->id(), permission_unit));
|
|
account_permissions.mutable_account_permissions()->insert(
|
|
google::protobuf::MapPair<
|
|
uint32_t, bts::api::admin::UserAccountPermissionUnit>(
|
|
account_btc->id(), permission_unit));
|
|
account_permissions.mutable_account_permissions()->insert(
|
|
google::protobuf::MapPair<
|
|
uint32_t, bts::api::admin::UserAccountPermissionUnit>(
|
|
account_eth->id(), permission_unit));
|
|
|
|
set_user_accounts(user_1, account_permissions);
|
|
set_user_accounts(user_2, account_permissions);
|
|
set_user_accounts(user_3, account_permissions);
|
|
|
|
// add cme and sim account data
|
|
bts::api::admin::ExchangeAccountData exchange_account_data;
|
|
exchange_account_data.mutable_cme_account_data()->set_cti(
|
|
bts::api::orderman::CTICode::CTI_CODE_CTI_CODE1);
|
|
exchange_account_data.mutable_cme_account_data()->set_origin(
|
|
bts::api::orderman::CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM);
|
|
exchange_account_data.mutable_cme_account_data()->set_clearing_account(
|
|
parent_account->name());
|
|
|
|
exchange_account_data.mutable_ice_account_data()->set_cti(
|
|
bts::api::orderman::CTICode::CTI_CODE_UNDEFINED);
|
|
exchange_account_data.mutable_ice_account_data()->set_origin(
|
|
bts::api::orderman::CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM);
|
|
exchange_account_data.mutable_ice_account_data()->set_clearing_account(
|
|
parent_account->name());
|
|
exchange_account_data.mutable_ice_account_data()->set_clearing_firm("649");
|
|
|
|
exchange_account_data.mutable_sim_account_data()->set_cti(
|
|
bts::api::orderman::CTICode::CTI_CODE_CTI_CODE1);
|
|
exchange_account_data.mutable_sim_account_data()->set_origin(
|
|
bts::api::orderman::CustomerOrFirm::CUSTOMER_OR_FIRM_FIRM);
|
|
exchange_account_data.mutable_sim_account_data()->set_clearing_account(
|
|
parent_account->name());
|
|
set_account_exchange_data(parent_account, exchange_account_data);
|
|
|
|
exchange_account_data.mutable_cme_account_data()->set_clearing_account(
|
|
account_1->name());
|
|
exchange_account_data.mutable_ice_account_data()->set_clearing_account(
|
|
account_1->name());
|
|
exchange_account_data.mutable_sim_account_data()->set_clearing_account(
|
|
account_1->name());
|
|
set_account_exchange_data(account_1, exchange_account_data);
|
|
|
|
exchange_account_data.mutable_cme_account_data()->set_clearing_account(
|
|
account_2->name());
|
|
exchange_account_data.mutable_ice_account_data()->set_clearing_account(
|
|
account_2->name());
|
|
exchange_account_data.mutable_sim_account_data()->set_clearing_account(
|
|
account_2->name());
|
|
set_account_exchange_data(account_2, exchange_account_data);
|
|
|
|
exchange_account_data.mutable_cme_account_data()->set_clearing_account(
|
|
account_3->name());
|
|
exchange_account_data.mutable_ice_account_data()->set_clearing_account(
|
|
account_3->name());
|
|
exchange_account_data.mutable_sim_account_data()->set_clearing_account(
|
|
account_3->name());
|
|
set_account_exchange_data(account_3, exchange_account_data);
|
|
|
|
exchange_account_data.mutable_ice_account_data()->set_clearing_account(
|
|
account_4->name());
|
|
set_account_exchange_data(account_4, exchange_account_data);
|
|
|
|
// add cme and sim user data
|
|
bts::api::admin::ExchangeUserData exchange_user_data;
|
|
exchange_user_data.mutable_cme_data()->set_operator_id(
|
|
"op_id_" + user_1->name());
|
|
exchange_user_data.mutable_cme_data()->set_location("us,nc");
|
|
|
|
exchange_user_data.mutable_ice_data()->set_operator_id(
|
|
"op_id_" + user_1->name());
|
|
exchange_user_data.mutable_ice_data()->set_company_id(51251);
|
|
exchange_user_data.mutable_ice_data()->set_authorized_trader("bluetrd-fx");
|
|
exchange_user_data.mutable_ice_data()->set_authorized_group("Group");
|
|
exchange_user_data.mutable_ice_data()->set_password("Starts123");
|
|
exchange_user_data.mutable_ice_data()->set_mifid_direct_electronic_access(
|
|
-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_trading_capacity(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_liquidity_provision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_commodity_deriv_indicator(
|
|
-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_investment_decision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_execution_decision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_client_id_code(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_id(1);
|
|
|
|
exchange_user_data.mutable_sim_data()->set_operator_id(
|
|
"op_id_" + user_1->name());
|
|
exchange_user_data.mutable_sim_data()->set_location("us,nc");
|
|
set_user_exchange_data(user_1, exchange_user_data);
|
|
|
|
exchange_user_data.mutable_cme_data()->set_operator_id(
|
|
"op_id_" + user_2->name());
|
|
exchange_user_data.mutable_cme_data()->set_location("us,nc");
|
|
|
|
exchange_user_data.mutable_ice_data()->set_operator_id(
|
|
"op_id_" + user_2->name());
|
|
exchange_user_data.mutable_ice_data()->set_company_id(51251);
|
|
exchange_user_data.mutable_ice_data()->set_authorized_trader("bluetrd-fx");
|
|
exchange_user_data.mutable_ice_data()->set_authorized_group("Group");
|
|
exchange_user_data.mutable_ice_data()->set_password("Starts123");
|
|
exchange_user_data.mutable_ice_data()->set_mifid_direct_electronic_access(
|
|
-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_trading_capacity(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_liquidity_provision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_commodity_deriv_indicator(
|
|
-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_investment_decision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_execution_decision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_client_id_code(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_id(1);
|
|
|
|
exchange_user_data.mutable_sim_data()->set_operator_id(
|
|
"op_id_" + user_2->name());
|
|
exchange_user_data.mutable_sim_data()->set_location("us,nc");
|
|
set_user_exchange_data(user_2, exchange_user_data);
|
|
|
|
exchange_user_data.mutable_cme_data()->set_operator_id(
|
|
"op_id_" + user_3->name());
|
|
exchange_user_data.mutable_cme_data()->set_location("us,nc");
|
|
|
|
exchange_user_data.mutable_ice_data()->set_operator_id(
|
|
"op_id_" + user_3->name());
|
|
exchange_user_data.mutable_ice_data()->set_company_id(51251);
|
|
exchange_user_data.mutable_ice_data()->set_authorized_trader("bluetrd-fx");
|
|
exchange_user_data.mutable_ice_data()->set_authorized_group("Group");
|
|
exchange_user_data.mutable_ice_data()->set_password("Starts123");
|
|
exchange_user_data.mutable_ice_data()->set_mifid_direct_electronic_access(
|
|
-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_trading_capacity(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_liquidity_provision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_commodity_deriv_indicator(
|
|
-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_investment_decision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_execution_decision(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_client_id_code(-1);
|
|
exchange_user_data.mutable_ice_data()->set_mifid_id(1);
|
|
|
|
exchange_user_data.mutable_sim_data()->set_operator_id(
|
|
"op_id_" + user_3->name());
|
|
exchange_user_data.mutable_sim_data()->set_location("us,nc");
|
|
set_user_exchange_data(user_3, exchange_user_data);
|
|
|
|
// associate all connections to all accounts
|
|
for (int i = 0; i < data.connections_size(); i++) {
|
|
std::string conn_name = data.connections(i).name();
|
|
for (int j = 0; j < data.accounts_size(); j++)
|
|
data.mutable_accounts(j)
|
|
->mutable_connections()
|
|
->add_exchange_connection_names(conn_name);
|
|
}
|
|
|
|
// add prod limit for ACC A
|
|
add_product_position_limits(
|
|
parent_account, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_FUTURE, 50000);
|
|
add_product_position_limits(
|
|
parent_account, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_SPREAD, 50000);
|
|
add_product_position_limits(
|
|
parent_account, api::Venue::VENUE_SIM,
|
|
api::SecurityType::SECURITYTYPE_FUTURE, 50000);
|
|
add_product_position_limits(
|
|
parent_account, api::Venue::VENUE_SIM,
|
|
api::SecurityType::SECURITYTYPE_SPREAD, 50000);
|
|
|
|
// security clip sizes for ACC A
|
|
add_security_clip_sizes_to_account(
|
|
parent_account, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_FUTURE, 50);
|
|
add_security_clip_sizes_to_account(
|
|
parent_account, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_SPREAD, 50);
|
|
add_security_clip_sizes_to_account(
|
|
parent_account, api::Venue::VENUE_SIM,
|
|
api::SecurityType::SECURITYTYPE_FUTURE, 50);
|
|
add_security_clip_sizes_to_account(
|
|
parent_account, api::Venue::VENUE_SIM,
|
|
api::SecurityType::SECURITYTYPE_SPREAD, 50);
|
|
|
|
// add sec limit for ACC A1
|
|
// cme
|
|
add_security_position_limits(
|
|
account_1, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_FUTURE);
|
|
add_security_position_limits(
|
|
account_1, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_SPREAD);
|
|
add_security_position_limits(
|
|
account_1, api::Venue::VENUE_SIM,
|
|
api::SecurityType::SECURITYTYPE_FUTURE);
|
|
add_security_position_limits(
|
|
account_1, api::Venue::VENUE_SIM,
|
|
api::SecurityType::SECURITYTYPE_SPREAD);
|
|
|
|
// add prod limit for ACC A1
|
|
add_product_position_limits(
|
|
account_1, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_FUTURE, 100000);
|
|
add_product_position_limits(
|
|
account_1, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_SPREAD, 100000);
|
|
add_product_position_limits(
|
|
account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE,
|
|
100000);
|
|
add_product_position_limits(
|
|
account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD,
|
|
100000);
|
|
|
|
// security clip sizes for ACC A1
|
|
add_security_clip_sizes_to_account(
|
|
account_1, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_FUTURE, 100);
|
|
add_security_clip_sizes_to_account(
|
|
account_1, api::Venue::VENUE_GLBX,
|
|
api::SecurityType::SECURITYTYPE_SPREAD, 100);
|
|
add_security_clip_sizes_to_account(
|
|
account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_FUTURE,
|
|
100);
|
|
add_security_clip_sizes_to_account(
|
|
account_1, api::Venue::VENUE_SIM, api::SecurityType::SECURITYTYPE_SPREAD,
|
|
100);
|
|
|
|
// ICE limits
|
|
add_product_position_limits(
|
|
account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_FUTURE,
|
|
50000);
|
|
add_product_position_limits(
|
|
account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_SPREAD,
|
|
50000);
|
|
add_security_clip_sizes_to_account(
|
|
account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_FUTURE,
|
|
50);
|
|
add_security_clip_sizes_to_account(
|
|
account_4, api::Venue::VENUE_ICE, api::SecurityType::SECURITYTYPE_SPREAD,
|
|
50);
|
|
}
|
|
bool AdminServiceUtils::has_id(uint32_t id) { return id > 0; }
|
|
bool AdminServiceUtils::is_symbol_set(const std::string &symbol) {
|
|
return symbol != "*";
|
|
}
|
|
void AdminServiceUtils::get_spread_prod_qty(
|
|
const api::Security &s,
|
|
std::map<std::string, double> &out_map,
|
|
double mult) {
|
|
if (s.has_spread())
|
|
for (const auto &leg : s.spread().legs()) {
|
|
auto effective_leg_mult =
|
|
mult * (leg.side() == api::Side::SIDE_BUY ? 1.0 : -1.0) *
|
|
std::abs(leg.quantity());
|
|
get_spread_prod_qty(leg.security(), out_map, effective_leg_mult);
|
|
}
|
|
else
|
|
out_map[s.symbol()] = mult + out_map[s.symbol()];
|
|
}
|
|
bool AdminServiceUtils::residual_pos_spread(const api::Security &s) {
|
|
if (!s.has_spread())
|
|
return false;
|
|
std::map<std::string, double> prod_qty_map;
|
|
get_spread_prod_qty(s, prod_qty_map, 1.0);
|
|
for (const auto &kv : prod_qty_map)
|
|
if (std::abs(kv.second) > 0.0000001)
|
|
return true;
|
|
return false;
|
|
}
|
|
} // namespace admin
|
|
} // namespace bts
|