Files
spark/src/lib/api/service_helpers/AdminServiceUtils.cpp
T

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