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

1815 lines
86 KiB
C++

#include "lib/api/services/AdminService.server.pb.h"
#include "lib/api/service_helpers/AdminServiceUtils.h"
#include "lib/md/get_symbols.h"
#include "lib/config/protos/cme_reference_data.pb.h"
#include "lib/config/protos/jetfix.pb.h"
#include "lib/config/config.h"
#include "lib/config/protos/system.pb.h"
#include <sstream>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>
namespace bts{
namespace admin{
using namespace bts::api::admin;
using namespace bts::api::orderman;
////////////////////////////////////////////
// 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_BTS:
case api::Venue::VENUE_CBOE:
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: {
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_CBOE:
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.platform()) {
case config::JetFIX::Connection::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 config::JetFIX::Connection::CBOE:
break;
case config::JetFIX::Connection::SIM:
case config::JetFIX::Connection::SIMICE:
connection.mutable_sim_connection();
add_connection(admin_data,connection);
break;
case config::JetFIX::Connection::ICE:
connection.mutable_ice_connection()->set_sender_compid(c.sender_compid());
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;
}
SecurityRiskLimitUnit const* AdminServiceUtils::get_sec_limit (
const AdminData& data,
uint32_t account_id,
uint32_t sec_key){
const BTSAccount* acct_ptr = find_account(data, account_id,false);
if(acct_ptr != nullptr){
if(acct_ptr->has_proprietary_risk_limits()){
const auto& prop_limits = acct_ptr->proprietary_risk_limits();
for (const auto& l : prop_limits.security_limits()){
if(l.security_key() == sec_key)
return &l;
}
}
}
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_BTS:
case api::Venue::VENUE_CBOE:
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_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_UNSET:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
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());
// prop_limits are not overwritten when the account is updated
// from the risk portal
const ProprietaryRiskLimits prop_limits = account_ptr->proprietary_risk_limits();
account_ptr->CopyFrom(updated_account);
account_ptr->mutable_proprietary_risk_limits()->CopyFrom(prop_limits);
}
}
void AdminServiceUtils::update_proprietary_risk(
AdminData& data,
const ProprietaryRiskLimitsAPIArgument& arg,
AdminServiceOperationResult& result){
BTSAccount* acct_ptr = find_account(data,arg.account_id());
if(acct_ptr == nullptr){
result.set_is_success(false);
result.set_error_text("Could not find account id");
return;
}
else{
result.set_is_success(true);
acct_ptr->mutable_proprietary_risk_limits()->CopyFrom(arg.proprietary_risk_limits());
}
}
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_UNSET:
case api::Venue::VENUE_BTS:
case api::Venue::VENUE_CBOE:
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_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_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::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)
{
std::vector<md::UserSymbol> symbols;
md::get_system_md_symbols(venue, sec_type,&symbols);
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)
{
std::vector<md::UserSymbol> symbols;
md::get_system_md_symbols(venue, sec_type,&symbols);
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);
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));
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;
}
}}