Compare commits
5
Commits
ls
...
development.crypto
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66ad51280f | ||
|
|
029edd8a86 | ||
|
|
dfdcbab2a0 | ||
|
|
6d7c0702f0 | ||
|
|
86eaddea93 |
No files matched your search
@@ -39,6 +39,7 @@ SPARKD__CONFIG_DIR=src/server/sparkd/configurations/dev
|
||||
# Defaults to a volume named "sparkd_<config_port>" (e.g., sparkd_8000).
|
||||
# SPARKD__DATA_DIR=/home/bts/sparkdata/data
|
||||
SPARKD__SOURCE_DIR=install/sparkd-release-gcc
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/ubuntu/8000/sparkdata/conf/
|
||||
SPARKD__CONFIG_PORT=8000
|
||||
SPARKD__QUICKBUS_PORT=8001
|
||||
SPARKD__SIM_FIX_PORT=8002
|
||||
|
||||
Vendored
+1
-1
@@ -326,4 +326,4 @@
|
||||
"description": "Test to run",
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,43 @@ services:
|
||||
resources:
|
||||
limits:
|
||||
memory: "${SPARKD__MEMORY:-4gb}"
|
||||
sparkd-symbols:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
|
||||
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/sparkdata/conf
|
||||
build:
|
||||
dockerfile: src/server/sparkd/Dockerfile
|
||||
args:
|
||||
- IMAGE=${SPARKD__IMAGE}
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
|
||||
command: >
|
||||
sh -c "
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/sparkdata/data
|
||||
if [ -e "/home/bts/sparkdata/data/logging.sparkd/log" ]; then
|
||||
mv "/home/bts/sparkdata/data/logging.sparkd/log" "/home/bts/sparkdata/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
|
||||
fi
|
||||
ls -alh /home/bts/sparkdata/conf/
|
||||
cat /home/bts/sparkdata/conf/.env.local
|
||||
if [ -e "/home/bts/sparkdata/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/sparkdata/conf/.env.local'
|
||||
set -a
|
||||
. /home/bts/sparkdata/conf/.env.local
|
||||
set +a
|
||||
fi
|
||||
./sparkd run"
|
||||
env_file:
|
||||
- .env
|
||||
- ${SPARKD__CONFIG_DIR}/.env
|
||||
ports:
|
||||
- "${SPARKD__CONFIG_PORT}:${SPARKD__CONFIG_PORT}"
|
||||
- "${SPARKD__QUICKBUS_PORT}:${SPARKD__QUICKBUS_PORT}"
|
||||
- "${SPARKD__SIM_FIX_PORT}:${SPARKD__SIM_FIX_PORT}"
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "${SPARKD__MEMORY:-4gb}"
|
||||
|
||||
sparkd-tail:
|
||||
image: bluetradingsystems/linux_dotnet7
|
||||
|
||||
@@ -55,24 +55,24 @@ OkxExecutionGateway::~OkxExecutionGateway() {}
|
||||
enum class OkxExecutionState { OFF, STARTED, LOGGED_IN, SUBSCIRBED };
|
||||
void OkxExecutionGateway::send_msgs(
|
||||
std::vector<OrderMsg> const &msgs, trace::CorID) {
|
||||
LOG(OrderMan,Info,"ExecutionGateway::send_msgs" );
|
||||
LOG(OrderMan, Info, "ExecutionGateway::send_msgs");
|
||||
for (const auto &msg : msgs) {
|
||||
std::visit(
|
||||
[this](auto &&order) {
|
||||
using T = std::decay_t<decltype(order)>;
|
||||
if constexpr (std::is_same_v<T, CreateOrderMsg>) {
|
||||
LOG(OrderMan,Warn,"ExecutionGateway::CreateOrderMsg" );
|
||||
LOG(OrderMan, Warn, "ExecutionGateway::CreateOrderMsg");
|
||||
launch_new_order(order);
|
||||
|
||||
|
||||
} else if constexpr (std::is_same_v<T, CancelOrderMsg>) {
|
||||
LOG(OrderMan,Warn,"ExecutionGateway::CancelOrderMsg" );
|
||||
LOG(OrderMan, Warn, "ExecutionGateway::CancelOrderMsg");
|
||||
cancel_order(order);
|
||||
} else if constexpr (std::is_same_v<T, CancelReplaceOrderMsg>) {
|
||||
LOG(OrderMan,Warn,"ExecutionGateway::CancelReplaceOrderMsg" );
|
||||
LOG(OrderMan, Warn, "ExecutionGateway::CancelReplaceOrderMsg");
|
||||
modify_order(order);
|
||||
} else if constexpr (std::is_same_v<T, RFQMsg>) {
|
||||
// Handle RFQMsg if necessary
|
||||
// adapter->handle_rfq(order); // Example placeholder
|
||||
// Handle RFQMsg if necessary
|
||||
// adapter->handle_rfq(order); // Example placeholder
|
||||
}
|
||||
},
|
||||
msg);
|
||||
@@ -94,7 +94,8 @@ struct OkxExecutionGateway::PImpl {
|
||||
const std::string passphrase = config::get<config::OkxExeCfg>().passphrase();
|
||||
const std::string url =
|
||||
config::get<config::OkxExeCfg>().ws_url() + "/ws/v5/private";
|
||||
const bool simulated_trading = config::get<config::OkxExeCfg>().simulated_trading();
|
||||
const bool simulated_trading =
|
||||
config::get<config::OkxExeCfg>().simulated_trading();
|
||||
const std::string tdmode = config::get<config::OkxExeCfg>().tdmode();
|
||||
const core::TimeSpan connect_timeout = core::TimeSpan::from_seconds(0);
|
||||
const core::TimeSpan pong_timeout = core::TimeSpan::from_seconds(
|
||||
@@ -124,7 +125,8 @@ struct OkxExecutionGateway::PImpl {
|
||||
}
|
||||
}
|
||||
|
||||
static void dummy(std::shared_ptr<const ExecutionReport>, const trace::CorID &) {
|
||||
static void dummy(
|
||||
std::shared_ptr<const ExecutionReport>, const trace::CorID &) {
|
||||
LOG(OrderMan, Error, "OnixFixListener::Dummy fired");
|
||||
}
|
||||
void setCallback(const OnExeReport &callback) {
|
||||
@@ -185,7 +187,7 @@ struct OkxExecutionGateway::PImpl {
|
||||
Price(std::stod(order.at("lastPx").get<std::string>()));
|
||||
report.avg_price = Price(std::stod(order.at("avgPx").get<std::string>()));
|
||||
report.last_shares = Quantity::create_new(
|
||||
std::stod(order.at("fillSz").get<std::string>()));
|
||||
std::stod(order.at("fillSz").get<std::string>()));
|
||||
|
||||
//there are algos, like spreader
|
||||
// that are super sensitive to messages and cancel themselves. To avoid
|
||||
@@ -195,29 +197,28 @@ struct OkxExecutionGateway::PImpl {
|
||||
// Alternatively we can change the spreader to not do that. Right not this
|
||||
// seems to be the better choice
|
||||
if (!(order.at("code").get<std::string>() == "0")) {
|
||||
report.msg = order.at("msg").get<std::string>();
|
||||
}
|
||||
report.msg = order.at("msg").get<std::string>();
|
||||
}
|
||||
|
||||
//report can be new order, cancel order, order filled, replace order, and partial fill or errror
|
||||
//new order, cancelled and order filled dont need special handling, error gets handled above
|
||||
//for other three we will look for fields that are only specific to the respectives types
|
||||
// if (!(order.at("cancelSource").get<std::string>() == "")) {
|
||||
|
||||
//report can be new order, cancel order, order filled, replace order, and partial fill or errror
|
||||
//new order, cancelled and order filled dont need special handling, error gets handled above
|
||||
//for other three we will look for fields that are only specific to the respectives types
|
||||
// if (!(order.at("cancelSource").get<std::string>() == "")) {
|
||||
|
||||
// }
|
||||
// }
|
||||
if (!(order.at("amendSource").get<std::string>() == "")) {
|
||||
if((order.at("amendResult").get<std::string>() == "0"))
|
||||
if ((order.at("amendResult").get<std::string>() == "0"))
|
||||
report.exec_type = api::orderman::ExecType::EXEC_TYPE_REPLACED;
|
||||
else{
|
||||
else {
|
||||
LOG(OrderMan, Warn, "order:{} replace rejected", report.order_key);
|
||||
report.msg = order.at("msg").get<std::string>();
|
||||
}
|
||||
}
|
||||
} else if (!(order.at("fillSz").get<std::string>() == "0")) {
|
||||
utils::Uuid guid;
|
||||
std::string fill_id = guid.to_text_string();
|
||||
to_array(fill_id, &report.exchange_fill_id.value());
|
||||
utils::Uuid guid;
|
||||
std::string fill_id = guid.to_text_string();
|
||||
to_array(fill_id, &report.exchange_fill_id.value());
|
||||
}
|
||||
|
||||
|
||||
// report.transact_time = ExchangeTimeStampVar(std::stoll(order.at("uTime").get<std::string>()));
|
||||
ExchangeTimeStamp64 now = ExchangeTimeStamp64(datetime::unix_nano_now());
|
||||
report.transact_time = now;
|
||||
@@ -228,14 +229,14 @@ struct OkxExecutionGateway::PImpl {
|
||||
bts_assert_msgf(
|
||||
false, "Websocket stream client disconnected. {}", ec.message());
|
||||
}
|
||||
// fills execution report form basic_json and writes it to
|
||||
// buffered_exec_reps, which is picked up from the other thread
|
||||
// and passed over to the order infrastructure
|
||||
void _push_execution_report(const nlohmann::basic_json<> &order) {
|
||||
ExecutionReport er;
|
||||
get_exe_report(order, er);
|
||||
buffered_exec_reps.push(std::make_shared<ExecutionReport>(std::move(er)));
|
||||
}
|
||||
// fills execution report form basic_json and writes it to
|
||||
// buffered_exec_reps, which is picked up from the other thread
|
||||
// and passed over to the order infrastructure
|
||||
void _push_execution_report(const nlohmann::basic_json<> &order) {
|
||||
ExecutionReport er;
|
||||
get_exe_report(order, er);
|
||||
buffered_exec_reps.push(std::make_shared<ExecutionReport>(std::move(er)));
|
||||
}
|
||||
void on_message(const std::string &msg_str) {
|
||||
LOG(OrderMan, Info, "okxlistener::on_message. {}", msg_str);
|
||||
nlohmann::json msg;
|
||||
@@ -279,21 +280,22 @@ struct OkxExecutionGateway::PImpl {
|
||||
}
|
||||
|
||||
const auto &data = msg.at("data");
|
||||
|
||||
|
||||
|
||||
for (const nlohmann::basic_json<> &order : data) {
|
||||
int orderkey = 0;
|
||||
try {
|
||||
int orderkey = 0;
|
||||
try {
|
||||
int temp = std::stoi(order.at("clOrdId").get<std::string>());
|
||||
orderkey = temp;
|
||||
}catch (...) {
|
||||
}
|
||||
if(orderkey ==0){
|
||||
LOG(OrderMan, Error, "okxlistener::on_message GOT ER FOR ORDER NOT ENTERED FROM SYSTEM. {}", msg_str);
|
||||
} catch (...) {
|
||||
}
|
||||
if (orderkey == 0) {
|
||||
LOG(OrderMan, Error,
|
||||
"okxlistener::on_message GOT ER FOR ORDER NOT ENTERED FROM "
|
||||
"SYSTEM. {}",
|
||||
msg_str);
|
||||
continue;
|
||||
}
|
||||
_push_execution_report(order);
|
||||
}
|
||||
_push_execution_report(order);
|
||||
}
|
||||
}
|
||||
void start() {
|
||||
@@ -456,8 +458,8 @@ struct OkxExecutionGateway::PImpl {
|
||||
};
|
||||
void OkxExecutionGateway::start() { me_->start(); }
|
||||
OnGwStatusChange &OkxExecutionGateway::on_gw_status_change() {
|
||||
return me_->on_gw_status_change;
|
||||
}
|
||||
return me_->on_gw_status_change;
|
||||
}
|
||||
void OkxExecutionGateway::modify_order(
|
||||
const CancelReplaceOrderMsg &msg) { //confirm will have everything
|
||||
try {
|
||||
@@ -474,7 +476,7 @@ void OkxExecutionGateway::modify_order(
|
||||
std::to_string(msg.create_fields.quantity.full_value()));
|
||||
auto headers = OkxUtils::createHeaders(
|
||||
me_->api_key, me_->passphrase, me_->secret_key, "POST", REQUEST_PATH,
|
||||
me_->simulated_trading,body);
|
||||
me_->simulated_trading, body);
|
||||
// Generate and log the curl command
|
||||
std::string curlCommand = OkxUtils::generateCurlCommand(
|
||||
config::get<config::OkxExeCfg>().rest_url() + REQUEST_PATH, headers,
|
||||
@@ -488,7 +490,8 @@ void OkxExecutionGateway::modify_order(
|
||||
if (suc) {
|
||||
LOG(md, Info, "Http get succeeded {}", res.body);
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}", res.code, res.errors, res.body);
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}",
|
||||
res.code, res.errors, res.body);
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
const std::string err = ex.what();
|
||||
@@ -496,17 +499,17 @@ void OkxExecutionGateway::modify_order(
|
||||
}
|
||||
}
|
||||
void OkxExecutionGateway::dispatch_incoming_fix_messages() {
|
||||
if (me_->buffered_exec_reps.empty()) {
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<ExecutionReport> er;
|
||||
while (me_->buffered_exec_reps.try_pop(er)) {
|
||||
trace::CorID cid = {};
|
||||
LOG(OrderMan, Info,
|
||||
"OkxExecutionGateway::dispatch_incoming_fix_messages er: {} ",
|
||||
er->to_string());
|
||||
me_->cb(std::move(er), cid);
|
||||
}
|
||||
if (me_->buffered_exec_reps.empty()) {
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<ExecutionReport> er;
|
||||
while (me_->buffered_exec_reps.try_pop(er)) {
|
||||
trace::CorID cid = {};
|
||||
LOG(OrderMan, Info,
|
||||
"OkxExecutionGateway::dispatch_incoming_fix_messages er: {} ",
|
||||
er->to_string());
|
||||
me_->cb(std::move(er), cid);
|
||||
}
|
||||
}
|
||||
OnExeReport &OkxExecutionGateway::on_exe_report() { return me_->cb; }
|
||||
OnCancelReject &OkxExecutionGateway::on_cancel_reject() {
|
||||
@@ -538,12 +541,12 @@ void OkxExecutionGateway::launch_new_order(const CreateOrderMsg &msg) {
|
||||
const std::string ord_type =
|
||||
FIX::string_toLower(ord_full_name.substr(pos + suffix.size()));
|
||||
const std::string body = fmt::format(
|
||||
body_template, msg.security->okx().security_desc(),me_->tdmode, side, ord_type,
|
||||
price, quantity, msg.key);
|
||||
body_template, msg.security->okx().security_desc(), me_->tdmode, side,
|
||||
ord_type, price, quantity, msg.key);
|
||||
http::HttpResponse res;
|
||||
auto headers = OkxUtils::createHeaders(
|
||||
me_->api_key, me_->passphrase, me_->secret_key, "POST", REQUEST_PATH,
|
||||
me_->simulated_trading,body);
|
||||
me_->simulated_trading, body);
|
||||
// Generate and log the curl command
|
||||
std::string curlCommand = OkxUtils::generateCurlCommand(
|
||||
config::get<config::OkxExeCfg>().rest_url() + REQUEST_PATH, headers,
|
||||
@@ -556,30 +559,33 @@ void OkxExecutionGateway::launch_new_order(const CreateOrderMsg &msg) {
|
||||
const auto &[suc, top_msg] = OkxUtils::orderAccepted(res.body);
|
||||
|
||||
if (suc) {
|
||||
LOG(md, Info, "Http get succeeded {}", res.body);
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_PENDING_NEW;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_PENDING_NEW;
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}", res.code, res.errors, res.body);
|
||||
OkxUtils::populateCreateOrderFields(er, msg);
|
||||
er.price = msg.price;
|
||||
er.quantity = msg.quantity;
|
||||
er.filled_quantity = 0;
|
||||
er.last_shares = 0;
|
||||
er.leg_security = nullptr;
|
||||
er.avg_price = Price(0);
|
||||
ExchangeTimeStamp64 now = ExchangeTimeStamp64(datetime::unix_nano_now());
|
||||
er.transact_time = now;
|
||||
er.order_key = msg.key;
|
||||
const auto &[id, ts, ex_msg] = OkxUtils::extractOrderInfo(res.body);
|
||||
er.exchange_order_id = ExchangeOrderID{OkxUtils::stringToFixedArray(id)};
|
||||
er.exec_type = api::orderman::ExecType::EXEC_TYPE_REJECTED;
|
||||
er.order_status = api::orderman::NATIVE_ORDER_STATUS_REJECTED;
|
||||
er.msg = ex_msg + " " + top_msg;
|
||||
me_->buffered_exec_reps.push(
|
||||
std::make_shared<ExecutionReport>(std::move(er)));
|
||||
LOG(md, Info, "Http get succeeded {}", res.body);
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_PENDING_NEW;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_PENDING_NEW;
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}",
|
||||
res.code, res.errors, res.body);
|
||||
OkxUtils::populateCreateOrderFields(er, msg);
|
||||
er.price = msg.price;
|
||||
er.quantity = msg.quantity;
|
||||
er.filled_quantity = 0;
|
||||
er.last_shares = 0;
|
||||
er.leg_security = nullptr;
|
||||
er.avg_price = Price(0);
|
||||
ExchangeTimeStamp64 now =
|
||||
ExchangeTimeStamp64(datetime::unix_nano_now());
|
||||
er.transact_time = now;
|
||||
er.order_key = msg.key;
|
||||
const auto &[id, ts, ex_msg] = OkxUtils::extractOrderInfo(res.body);
|
||||
er.exchange_order_id =
|
||||
ExchangeOrderID{OkxUtils::stringToFixedArray(id)};
|
||||
er.exec_type = api::orderman::ExecType::EXEC_TYPE_REJECTED;
|
||||
er.order_status = api::orderman::NATIVE_ORDER_STATUS_REJECTED;
|
||||
er.msg = ex_msg + " " + top_msg;
|
||||
me_->buffered_exec_reps.push(
|
||||
std::make_shared<ExecutionReport>(std::move(er)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Shut down all reactors if they exist.
|
||||
catch (const std::exception &ex) {
|
||||
const std::string err = ex.what();
|
||||
@@ -605,7 +611,7 @@ void OkxExecutionGateway::cancel_order(const CancelOrderMsg &msg) {
|
||||
body_template, msg.security->okx().security_desc(), msg.key);
|
||||
auto headers = OkxUtils::createHeaders(
|
||||
me_->api_key, me_->passphrase, me_->secret_key, "POST", REQUEST_PATH,
|
||||
me_->simulated_trading,body);
|
||||
me_->simulated_trading, body);
|
||||
// Generate and log the curl command
|
||||
std::string curlCommand = OkxUtils::generateCurlCommand(
|
||||
config::get<config::OkxExeCfg>().rest_url() + REQUEST_PATH, headers,
|
||||
@@ -630,7 +636,8 @@ void OkxExecutionGateway::cancel_order(const CancelOrderMsg &msg) {
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_PENDING_CANCEL;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_PENDING_CANCEL;
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}", res.code, res.errors, res.body);
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}",
|
||||
res.code, res.errors, res.body);
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_REJECTED;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_REJECTED;
|
||||
// er.msg = ex_msg + " " + top_msg;
|
||||
@@ -643,8 +650,7 @@ void OkxExecutionGateway::cancel_order(const CancelOrderMsg &msg) {
|
||||
OkxUtils::handleOkException("Cacnel order", err);
|
||||
}
|
||||
}
|
||||
} // namespace bts::orderman::okxexe
|
||||
|
||||
} // namespace bts::orderman
|
||||
|
||||
// ExecutionReport OkxExecutionAdapter::fire_dummy_modify_order_report(CancelReplaceOrderMsg msg) {
|
||||
// ExecutionReport *er_p = me_->create_exe_ptr();
|
||||
|
||||
@@ -156,23 +156,15 @@ void SpreaderOrder::_on_time(const bts::mercury::TimerEvent &t_event) {
|
||||
}
|
||||
}
|
||||
void SpreaderOrder::_on_book_update(const BookUpdateEvent &book_event) {
|
||||
if (book_event.key() == _bookkeeping_data().spread_sec_key()) {
|
||||
// TODO, update spread book
|
||||
_bookkeeping_data().spread_book = book_event.book;
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderOrder::_on_book_update spread book udpate, skey: {} "
|
||||
"bid: {}/{} a: {}/{}",
|
||||
book_event.key(), book_event.book.bid().at(0).price(),
|
||||
book_event.book.bid().at(0).size(),
|
||||
book_event.book.ask().at(0).price(),
|
||||
book_event.book.ask().at(0).size());
|
||||
return;
|
||||
}
|
||||
LOG(OrderMan, Diag,
|
||||
"SpreaderOrder::_on_book_update skey: {} bid: {}/{} a: {}/{}",
|
||||
book_event.key(), book_event.book.bid().at(0).price(),
|
||||
book_event.book.bid().at(0).size(), book_event.book.ask().at(0).price(),
|
||||
book_event.book.ask().at(0).size());
|
||||
if (book_event.key() == _bookkeeping_data().spread_sec_key()) {
|
||||
_bookkeeping_data().spread_book = book_event.book;
|
||||
return;
|
||||
}
|
||||
if (!_active)
|
||||
return;
|
||||
auto scoped = _order_services->log_scope(
|
||||
|
||||
@@ -108,7 +108,7 @@ class SpreaderOrder : public Order, public ISpreaderManager {
|
||||
public:
|
||||
// inherited function to return the OrderDefinition. asserts
|
||||
// if on_init_new has not been called yet
|
||||
const api::orderman::OrderDefinition &definition() const;
|
||||
const api::orderman::OrderDefinition &definition() const override;
|
||||
// this is the construction, can be slow
|
||||
void on_init_new(
|
||||
const bts::api::orderman::OrderDefinition &order_def,
|
||||
@@ -137,7 +137,11 @@ class SpreaderOrder : public Order, public ISpreaderManager {
|
||||
bts::orderman::OrderKey spreader_order_key() const override { return key(); }
|
||||
bts::TimeStamp current_time() const override { return _curr_timestamp; }
|
||||
const bts::orderman::Book &get_book(size_t leg_index) const override {
|
||||
return _bookkeeping_data().get_leg_data(leg_index).book();
|
||||
const SpreaderLegData &leg_data =
|
||||
_bookkeeping_data().get_leg_data(leg_index);
|
||||
const auto &rv = leg_data.book();
|
||||
return rv;
|
||||
//return _bookkeeping_data().get_leg_data(leg_index).book();
|
||||
}
|
||||
|
||||
const bts::orderman::Book &get_spread_book() const override {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "SpreaderFractionalQtyHelper.h"
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/domain_model/SecurityKey.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/orderman/ChildOrder.h"
|
||||
@@ -20,6 +21,10 @@ class IAlternateOrderGateway;
|
||||
// ii. create new quoter order
|
||||
class ISpreaderManager {
|
||||
public:
|
||||
// definition() was added when we expanded the spreader to add reverse hedging and sniper.
|
||||
// that needed spreader sid etc, which is all in the definition. Also spreader_order_key() can
|
||||
// retired
|
||||
virtual const api::orderman::OrderDefinition &definition() const = 0;
|
||||
virtual bts::orderman::OrderKey spreader_order_key() const = 0;
|
||||
virtual bts::TimeStamp current_time() const = 0;
|
||||
// this is a reference to the original book structure
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "LegPropertyData.h"
|
||||
#include "ISpreaderManager.h"
|
||||
#include "SpreaderUtils.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -10,11 +12,35 @@ LegPropertyData::LegPropertyData(
|
||||
const bts::api::ContractLeg &leg_contract,
|
||||
const bts::spark::LegSpreaderParams &leg_params,
|
||||
api::Side trading_side,
|
||||
bts::spark::ExecutionStrategy::SpreaderType spreader_quoting_type,
|
||||
bts::api::SyntheticContract::PriceCalc price_calc,
|
||||
double qty_tick_size)
|
||||
: _leg_index(leg_index), _leg_contract(leg_contract),
|
||||
_leg_params(leg_params), _trading_side(trading_side),
|
||||
|
||||
_price_calc(price_calc), _qty_tick_size(qty_tick_size) {
|
||||
switch (spreader_quoting_type) {
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REQUOTE: {
|
||||
_is_active_quoting = leg_params.has_quote_params();
|
||||
break;
|
||||
}
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REVERSE_HEDGE: {
|
||||
_is_active_quoting = leg_params.has_reverse_hedge_quote_params();
|
||||
break;
|
||||
}
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_SNIPER: {
|
||||
_is_active_quoting = leg_params.has_sniper_quote_params();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(OrderMan, Info,
|
||||
"LegPropertyData.cons leg_idx: "
|
||||
"{} sec_key: {} side: {}",
|
||||
|
||||
@@ -19,6 +19,7 @@ class LegPropertyData {
|
||||
const api::Side _trading_side;
|
||||
const bts::api::SyntheticContract::PriceCalc _price_calc;
|
||||
const double _qty_tick_size = 1.0;
|
||||
bool _is_active_quoting;
|
||||
|
||||
public:
|
||||
LegPropertyData(
|
||||
@@ -26,6 +27,9 @@ class LegPropertyData {
|
||||
const bts::api::ContractLeg &leg_contract,
|
||||
const bts::spark::LegSpreaderParams &leg_params,
|
||||
api::Side trading_side,
|
||||
bts::spark::ExecutionStrategy::SpreaderType spreader_quoting_type =
|
||||
bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REQUOTE,
|
||||
bts::api::SyntheticContract::PriceCalc price_calc =
|
||||
bts::api::SyntheticContract::PRICECALC_STANDARD,
|
||||
double qty_tick_size = 1.0);
|
||||
@@ -52,11 +56,7 @@ class LegPropertyData {
|
||||
double qty_tick_size() const { return _qty_tick_size; }
|
||||
// TODO: is_quoting
|
||||
//bool is_active_quoting() const { return _leg_params.is_active_quoting(); }
|
||||
bool is_active_quoting() const {
|
||||
return _leg_params.has_quote_params() ||
|
||||
_leg_params.has_reverse_hedge_quote_params() ||
|
||||
_leg_params.has_sniper_quote_params();
|
||||
}
|
||||
bool is_active_quoting() const { return _is_active_quoting; }
|
||||
bool is_net_change() const {
|
||||
return _price_calc == bts::api::SyntheticContract::PRICECALC_NET_CHANGE;
|
||||
}
|
||||
|
||||
@@ -273,7 +273,9 @@ void SingleLegQuoter::_transform_to_WAITING_FOR_IOC() {
|
||||
_switch_state(&_waiting_for_ioc_worker);
|
||||
}
|
||||
void SingleLegQuoter::_transform_to_WAITING_FOR_FIRST_ACK_CANCELLED() {
|
||||
bts_assert(_worker->state() == QuoterState::WAITING_FOR_FIRST_ACK);
|
||||
bts_assert(
|
||||
_worker->state() == QuoterState::WAITING_FOR_FIRST_ACK ||
|
||||
_worker->state() == QuoterState::WAITING_FOR_IOC);
|
||||
_switch_state(&_waiting_for_first_ack_cancelled_state_worker);
|
||||
}
|
||||
void SingleLegQuoter::_transform_to_WORKING() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/LegPropertyData.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderFractionalQtyHelper.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -41,6 +42,11 @@ SpreaderBookkeepingData::SpreaderBookkeepingData(
|
||||
_leg_data.emplace_back(
|
||||
spreader_pao_services, spreader_order_key, _n_legs, spreader_manager,
|
||||
quoter_ord_defs[i], hedger_ord_defs[i], leg_property_data);
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderBookkeepingData::cons leg_idx: {} quoter_ord_def: {} "
|
||||
"hedger_ord_defs: {}",
|
||||
i, utils::pb::to_string(quoter_ord_defs[i]),
|
||||
utils::pb::to_string(hedger_ord_defs[i]));
|
||||
bts_assert(
|
||||
_sec_key_to_index.find(leg_property_data.security_key()) ==
|
||||
_sec_key_to_index.end());
|
||||
|
||||
@@ -96,7 +96,10 @@ class SpreaderLegData {
|
||||
bts_assert(_is_quoting);
|
||||
return *_quoter;
|
||||
}
|
||||
const bts::orderman::Book &book() const { return _book; }
|
||||
const bts::orderman::Book &book() const {
|
||||
// book
|
||||
return _book;
|
||||
}
|
||||
Price settlement_price() const { return Price(_settlement_price.price()); }
|
||||
bool settlement_populated() const {
|
||||
return !os::is_nan(_settlement_price.price());
|
||||
@@ -162,6 +165,11 @@ class SpreaderLegData {
|
||||
book, _settlement_price, _leg_property_data.tick_size(),
|
||||
_leg_property_data.md_type(),
|
||||
bts::api::SyntheticContract::PRICECALC_STANDARD, _book);
|
||||
// LOG(OrderMan, Info,
|
||||
// "SpreaderLegData::update_book index: {} lpd_key: {} book: {} book "
|
||||
// "key: {}",
|
||||
// _leg_property_data.leg_index(), _leg_property_data.security_key(),
|
||||
// book, book.security_key());
|
||||
}
|
||||
void update_settlement_price(md::IntPrice price) {
|
||||
_settlement_price = price;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "SpreaderUtils.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/orderman/events/BookUpdateEvent.h"
|
||||
#include "lib/orderman/orderman_utils/Book.h"
|
||||
@@ -7,6 +8,7 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderBuilder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderPreActivationOrderServices.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include <sstream>
|
||||
namespace bts {
|
||||
@@ -67,6 +69,8 @@ bool SpreaderUtils::resolve_synthetic_spread(
|
||||
std::vector<bts::api::orderman::OrderDefinition> &out_quoter_defs,
|
||||
std::vector<bts::api::orderman::OrderDefinition> &out_hedger_defs,
|
||||
bool resolve_synthetic) {
|
||||
LOG(OrderMan, Info, "g/ {}",
|
||||
utils::pb::to_string(order_def));
|
||||
auto get_quote_time_enforce =
|
||||
[&](const spark::ExecutionStrategy &exec_strat,
|
||||
const spark::LegSpreaderParams &q_leg_params) {
|
||||
@@ -150,31 +154,32 @@ bool SpreaderUtils::resolve_synthetic_spread(
|
||||
->mutable_limit()
|
||||
->MergeFrom(api::orderman::LimitOrderDefinition());
|
||||
}
|
||||
|
||||
// if (leg_params.quote_params().has_quote_hidden())
|
||||
// quoter_order_def.set_time_in_force(
|
||||
// bts::api::orderman::TimeInForce::TIME_IN_FORCE_IOC);
|
||||
// else
|
||||
// quoter_order_def.set_time_in_force(
|
||||
// order_def.time_in_force());
|
||||
auto tif =
|
||||
get_quote_time_enforce(execution_strategy, leg_params);
|
||||
quoter_order_def.set_time_in_force(tif);
|
||||
|
||||
// hedger order def
|
||||
api::orderman::OrderDefinition hedger_order_def =
|
||||
quoter_order_def;
|
||||
hedger_order_def.mutable_custom_def()
|
||||
->mutable_limit()
|
||||
->MergeFrom(api::orderman::LimitOrderDefinition());
|
||||
quoter_order_def.set_time_in_force(order_def.time_in_force());
|
||||
//quoter_order_def.set_time_in_force(order_def.time_in_force());
|
||||
hedger_order_def.set_sub_type(
|
||||
bts::api::orderman::OrderSubType::
|
||||
ORDER_SUB_TYPE_HEDGING_LEG);
|
||||
LegPropertyData leg_property_data(
|
||||
leg_idx, leg, leg_params, leg_order_side,
|
||||
order_def.custom_def()
|
||||
.spreader()
|
||||
.execution_strategy()
|
||||
.spreader_type(),
|
||||
sec.synthetic().price_calc());
|
||||
out_resolved.push_back(leg_property_data);
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::resolve_synthetic_spread idx: {} "
|
||||
"quoter_order_def: {}",
|
||||
out_quoter_defs.size(),
|
||||
utils::pb::to_string(quoter_order_def));
|
||||
out_quoter_defs.push_back(quoter_order_def);
|
||||
out_hedger_defs.push_back(hedger_order_def);
|
||||
leg_idx++;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "lib/domain_model/Security.pb.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/jetfix/codec/FieldDefinitions.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/md/IntPrice.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/md/Shm/MDStructure.h"
|
||||
@@ -469,6 +470,12 @@ class SpreaderUtils {
|
||||
api::Side order_side,
|
||||
double tick_size,
|
||||
const Book &book) {
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::book_through_order_price_nticks: order_price: {} "
|
||||
"order_side: {} tick_size: {} -- bid: {}/{} ask: {}/{}",
|
||||
order_price, static_cast<int>(order_side), tick_size,
|
||||
book.bid().at(0).price(), book.bid().at(0).size(),
|
||||
book.ask().at(0).price(), book.ask().at(0).size());
|
||||
if (order_side == api::SIDE_BUY) {
|
||||
const md::PriceSize &top_ask = book.ask()[0];
|
||||
if (top_ask.size() == 0)
|
||||
@@ -487,20 +494,35 @@ class SpreaderUtils {
|
||||
}
|
||||
|
||||
static Price compute_order_price_through_book(
|
||||
const Book &book, api::Side order_side, int n_ticks) {
|
||||
const Book &book, api::Side order_side, double tick_size, int n_ticks) {
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::compute_order_price_through_book tick_size: {} "
|
||||
"n_ticks: {}",
|
||||
tick_size, n_ticks);
|
||||
switch (order_side) {
|
||||
case api::Side::SIDE_BUY: {
|
||||
if (n_ticks >= 0) {
|
||||
return Price(book.ask()[n_ticks].price());
|
||||
double top_ask = book.ask()[0].price();
|
||||
return Price(top_ask + tick_size * n_ticks);
|
||||
//return Price(book.ask()[n_ticks].price());
|
||||
} else {
|
||||
return Price(book.bid()[std::abs(n_ticks)].price());
|
||||
double top_bid = book.bid()[0].price();
|
||||
return Price(top_bid - tick_size * n_ticks);
|
||||
//return Price(book.bid()[std::abs(n_ticks)].price());
|
||||
}
|
||||
}
|
||||
case api::Side::SIDE_SELL: {
|
||||
if (n_ticks >= 0) {
|
||||
return Price(book.bid()[n_ticks].price());
|
||||
double top_bid = book.bid()[0].price();
|
||||
double rv = top_bid - tick_size * n_ticks;
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::compute_order_price_through_book top_bid: {} "
|
||||
"rv: {}",
|
||||
top_bid, rv);
|
||||
return Price(rv);
|
||||
} else {
|
||||
return Price(book.ask()[std::abs(n_ticks)].price());
|
||||
double top_ask = book.ask()[0].price();
|
||||
return Price(top_ask + tick_size * n_ticks);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
|
||||
+36
-15
@@ -1,7 +1,9 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForSizeStateWorker.h"
|
||||
#include "lib/domain_model/Security.pb.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/orderman/orderman_utils/Book.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/ISpreaderManager.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/LegPropertyData.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SingleLegQuoter.h"
|
||||
@@ -63,13 +65,6 @@ void QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act() {
|
||||
_quoter->_transform_to_END();
|
||||
return;
|
||||
} else {
|
||||
if (_quoter->_this_leg_data.leg_params()
|
||||
.has_reverse_hedge_quote_params()) {
|
||||
}
|
||||
if (_quoter->_this_leg_data.leg_params().has_sniper_quote_params()) {
|
||||
|
||||
} else if (_quoter->_this_leg_data.leg_params().has_quote_params()) {
|
||||
}
|
||||
auto spreader_q_type = _quoter->_spreader.get_spreader_quoting_type();
|
||||
switch (spreader_q_type) {
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
@@ -81,7 +76,7 @@ void QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act() {
|
||||
// only applicable for > 2 legged spreads
|
||||
_quoter->_commit_drivers(out_price);
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker sending order "
|
||||
"QuoterWaitingForSizeStateWorker (requoting) sending order "
|
||||
"key:{} price:{} quantity:{}",
|
||||
_quoter->_key(), out_price, out_quantity);
|
||||
// this is the only place where a quoter order is entered
|
||||
@@ -92,18 +87,27 @@ void QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act() {
|
||||
}
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REVERSE_HEDGE: {
|
||||
auto is_book_populated = [&](const Book &leg_book, api::Side bs) {
|
||||
const auto &book_side = leg_book.side(bs);
|
||||
return !os::is_nan(book_side.at(0).price());
|
||||
};
|
||||
const LegPropertyData &leg_data = _quoter->_this_leg_data;
|
||||
bts_assert(_quoter->_this_leg_data.leg_params()
|
||||
.has_reverse_hedge_quote_params());
|
||||
bts_assert(leg_data.leg_params().has_reverse_hedge_quote_params());
|
||||
const auto &rev_hedge_qparams =
|
||||
_quoter->_this_leg_data.leg_params().reverse_hedge_quote_params();
|
||||
leg_data.leg_params().reverse_hedge_quote_params();
|
||||
int n_ticks = rev_hedge_qparams.n_ticks();
|
||||
const Book &spread_book = _quoter->_spreader.get_spread_book();
|
||||
auto leg_qside = leg_data.trading_side();
|
||||
auto spread_side = _quoter->_spreader.definition().side();
|
||||
int book_through_ticks =
|
||||
SpreaderUtils::book_through_order_price_nticks(
|
||||
_quoter->_price_quantity_state.out_price(), leg_qside,
|
||||
_quoter->_this_leg_data.tick_size(), spread_book);
|
||||
_quoter->_price_quantity_state.target_spread_price(),
|
||||
// TODO (get it from the spread synth sec)
|
||||
spread_side, 0.1, spread_book);
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act("
|
||||
"reverse hedge) "
|
||||
"n_ticks: {} book_through_ticks: {}",
|
||||
n_ticks, book_through_ticks);
|
||||
if (book_through_ticks >= n_ticks) {
|
||||
// qty, shoot full size? (can min it by max available on hedge leg)
|
||||
//auto spr_qty = _quoter->_price_quantity_state.out_quantity();
|
||||
@@ -117,8 +121,25 @@ void QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act() {
|
||||
// price: (nticks into the opposite market)
|
||||
const Book &leg_book =
|
||||
_quoter->_spreader.get_book(leg_data.leg_index());
|
||||
bool leg_book_populated = is_book_populated(
|
||||
leg_book, SpreaderUtils::invert_side(leg_data.trading_side()));
|
||||
if (!leg_book_populated) {
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act "
|
||||
"(RH), quoting leg book is empty, not firing order");
|
||||
return;
|
||||
}
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act "
|
||||
"leg_book: {} k: {}",
|
||||
leg_book, leg_book.security_key());
|
||||
Price order_price = SpreaderUtils::compute_order_price_through_book(
|
||||
leg_book, leg_data.trading_side(), n_ticks);
|
||||
leg_book, leg_data.trading_side(), leg_data.tick_size(),
|
||||
n_ticks);
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker sending order in reverse "
|
||||
"hedging mode key: {} price: {} quantity: {}",
|
||||
_quoter->_key(), order_price, order_qty);
|
||||
_quoter->_place_order(order_price, order_qty);
|
||||
_quoter->_transform_to_WAITING_FOR_IOC();
|
||||
}
|
||||
|
||||
@@ -139,6 +139,9 @@ class SpreaderManagerForTest : public ISpreaderManager {
|
||||
return _bookkeeping_data.spread_book.value();
|
||||
//return get_book(0);
|
||||
}
|
||||
const api::orderman::OrderDefinition &definition() const override {
|
||||
return _bookkeeping_data.order_def();
|
||||
}
|
||||
// the caller can keep a reference to the returned type forever. the
|
||||
// data in the returned type is all const, so nothing will change
|
||||
// beneath it
|
||||
|
||||
@@ -40,7 +40,7 @@ message LegSpreaderParams
|
||||
}
|
||||
/// Legs can be quoted actively, or sent in reponse
|
||||
/// to fills
|
||||
bool is_active_quoting = 20;
|
||||
bool is_active_quoting = 20;
|
||||
bool enable_hedging = 30;
|
||||
QuoteParams quote_params = 40;
|
||||
ReverseHedgeQuoteParams reverse_hedge_quote_params = 43;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
SPARKD__CONFIG_DIR=src/server/sparkd/configurations/alphaworx_prod
|
||||
SPARKD__SHM_SIZE=8gb
|
||||
SPARKD__MEMORY=8gb
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/ubuntu/8000/sparkdata/conf/
|
||||
@@ -0,0 +1,4 @@
|
||||
SPARKD__CONFIG_DIR=src/server/sparkd/configurations/alphaworx_zen_hk_live
|
||||
SPARKD__SHM_SIZE=8gb
|
||||
SPARKD__MEMORY=8gb
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/bts/8000/sparkdata/conf/
|
||||
@@ -0,0 +1,6 @@
|
||||
* Connects to Binance and Okx PRODUCTION sites for market data and execution
|
||||
* Api keys NOT included
|
||||
* Configured for Alphaworx
|
||||
|
||||
To retrieve api keys, run "python init_env.py". It should dump them to a file
|
||||
called ".env.local".
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"api_key": "${BINANCE_API_KEY}",
|
||||
"secret_key": "${BINANCE_SECRET_KEY}",
|
||||
"account": "PROD",
|
||||
"rest_endpoint": "https://api.binance.com",
|
||||
"ws_endpoint": "wss://ws-api.binance.com:443/ws-api/v3",
|
||||
"ws_stream_endpoint": "wss://stream.binance.com:9443",
|
||||
"use_cross_margin_api": true
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"api_key": "${BINANCE_API_KEY}",
|
||||
"secret_key": "${BINANCE_SECRET_KEY}",
|
||||
"account": "PROD",
|
||||
"rest_endpoint": "https://fapi.binance.com",
|
||||
"ws_endpoint": "wss://ws-fapi.binance.com/ws-fapi/v1",
|
||||
"ws_stream_endpoint": "wss://fstream.binance.com",
|
||||
"use_cross_margin_api": false
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import botocore
|
||||
import json
|
||||
import os
|
||||
|
||||
from boto3.session import Session
|
||||
from botocore.exceptions import ClientError
|
||||
from fileinput import FileInput
|
||||
|
||||
|
||||
def update_env_file(path, env_vars: dict):
|
||||
"""Update or add vars in a .env file in place."""
|
||||
if not os.path.exists(path):
|
||||
with open(path, "w") as file:
|
||||
for k, v in env_vars.items():
|
||||
file.write(f"{k}={v}\n")
|
||||
return
|
||||
|
||||
with FileInput(path, inplace=True) as file:
|
||||
for line in file:
|
||||
if not line.startswith("#"):
|
||||
stripped: str = line.lstrip()
|
||||
key_len = stripped.find("=")
|
||||
if key_len >= 0:
|
||||
k = stripped[0:key_len]
|
||||
if k in env_vars:
|
||||
print(f"{k}={env_vars[k]}")
|
||||
del env_vars[k]
|
||||
continue
|
||||
print(line, end="")
|
||||
|
||||
if len(env_vars) > 0:
|
||||
with open(path, "a") as file:
|
||||
for k, v in env_vars.items():
|
||||
file.write(f"{k}={v}\n")
|
||||
|
||||
|
||||
def get_secret():
|
||||
secret_name = "alphaworx-binance-api-keys"
|
||||
region_name = "ap-northeast-1"
|
||||
profile_name = "AdministratorAccess-849458505639"
|
||||
session = Session(profile_name=profile_name)
|
||||
client = session.client(
|
||||
service_name="secretsmanager",
|
||||
region_name=region_name,
|
||||
)
|
||||
|
||||
def on_token_error(e: Exception):
|
||||
print(f"""
|
||||
Failed to get secret value. {e}
|
||||
Verify you are logged in to aws, then try again.
|
||||
|
||||
aws sso login --profile {profile_name}
|
||||
|
||||
If this error persists, verify you have access to these api keys.
|
||||
For more help or information, talk to John.
|
||||
""")
|
||||
|
||||
try:
|
||||
get_secret_value_response = client.get_secret_value(
|
||||
SecretId=secret_name)
|
||||
except ClientError as e:
|
||||
print(f"Failed to get secret value.\n{e}")
|
||||
raise e
|
||||
except botocore.exceptions.SSOTokenLoadError as tl_err:
|
||||
on_token_error(tl_err)
|
||||
return None
|
||||
except botocore.exceptions.TokenRetrievalError as tr_err:
|
||||
on_token_error(tr_err)
|
||||
return None
|
||||
return get_secret_value_response["SecretString"]
|
||||
|
||||
|
||||
def _run():
|
||||
this_dir = os.path.dirname(__file__)
|
||||
secret_str = get_secret()
|
||||
if secret_str is None:
|
||||
exit(1)
|
||||
secret = json.loads(secret_str)
|
||||
env_vars = {}
|
||||
if "api-key" in secret:
|
||||
env_vars["BINANCE_API_KEY"] = secret["api-key"]
|
||||
if "secret-key" in secret:
|
||||
env_vars["BINANCE_SECRET_KEY"] = secret["secret-key"]
|
||||
update_env_file(f"{this_dir}/.env.local", env_vars)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_run()
|
||||
@@ -0,0 +1,124 @@
|
||||
QuickbusCfg {
|
||||
value {
|
||||
node {
|
||||
reconnect_period_secs: 1
|
||||
hb_period_msecs: 15000
|
||||
max_missed_hbs: 5
|
||||
parent_host: ""
|
||||
parent_port: 0
|
||||
my_port: 0
|
||||
}
|
||||
client {
|
||||
reconnect_period_secs: 1
|
||||
hb_period_msecs: 15000
|
||||
max_missed_hbs: 5
|
||||
parent_host: @SystemConfig.config_ip
|
||||
parent_port: @Ports.qbus_port
|
||||
my_port: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JetFIX {
|
||||
value {
|
||||
connection {
|
||||
name: "binance_1"
|
||||
venue: VENUE_BINANCE
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
connection {
|
||||
name: "binance_usds_futures_1"
|
||||
venue: VENUE_BINANCE_USDS_FUTURES
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
connection {
|
||||
name: "okx_1"
|
||||
venue: VENUE_OKX
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MarketDataConfig {
|
||||
value {
|
||||
binance {
|
||||
num_depth_levels: 5
|
||||
url_rest_base: "https://api.binance.com"
|
||||
url_ws_base: "wss://stream.binance.com:9443"
|
||||
security_criteria {
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_SPOT
|
||||
symbols: @SymbolLists.list[Binance].symbol
|
||||
name_regexps: "USDC|USDT$"
|
||||
}
|
||||
}
|
||||
}
|
||||
binance_usds_futures {
|
||||
num_depth_levels: 5
|
||||
url_rest_base: "https://fapi.binance.com"
|
||||
url_ws_base: "wss://fstream.binance.com"
|
||||
security_criteria {
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_FUTURE
|
||||
symbols: @SymbolLists.list[BinanceUsdsFutures].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
okx {
|
||||
num_depth_levels: 5
|
||||
url_rest_base: "https://aws.okx.com"
|
||||
url_ws_base: "wss://wsaws.okx.com:8443"
|
||||
security_criteria {
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_SPOT
|
||||
symbols: @SymbolLists.list[OkxSpots].symbol
|
||||
}
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_FUTURE
|
||||
symbols: @SymbolLists.list[OkxFutures].symbol
|
||||
}
|
||||
}
|
||||
is_application_ping_pong_enabled: true
|
||||
application_ping_interval_ms: 20000
|
||||
application_pong_timeout_ms: 10000
|
||||
is_protocol_ping_pong_enabled: true
|
||||
protocol_ping_interval_ms: 60000
|
||||
protocol_pong_timeout_ms: 30000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotSimExecution {
|
||||
value {
|
||||
entries {
|
||||
venue: VENUE_BINANCE
|
||||
}
|
||||
entries {
|
||||
venue: VENUE_BINANCE_USDS_FUTURES
|
||||
}
|
||||
entries {
|
||||
venue: VENUE_OKX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OkxExeCfg {
|
||||
value {
|
||||
account: "PROD"
|
||||
ops_id: "op_id_bts"
|
||||
secret_key: "240038D7A28D7F9461247CFCB8E43710"
|
||||
api_key: "dc188532-c74c-4d40-affe-3c6bf4d0ca9a"
|
||||
passphrase: ":,7i%tA%ivfj%SCbX?Ut"
|
||||
ws_url: "wss://wsaws.okx.com:8443"
|
||||
rest_url: "https://www.okx.com"
|
||||
ws_ping_timeout_seconds: 10
|
||||
ws_ping_interval_seconds: 25
|
||||
ws_reconnect_interval_seconds: 5
|
||||
ws_reconnect_max_count: 5
|
||||
simulated_trading: false
|
||||
tdmode: "cross"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
SymbolLists {
|
||||
value {
|
||||
list {
|
||||
key: "Binance"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "PAXG"
|
||||
symbol: "PEPE"
|
||||
symbol: "S"
|
||||
symbol: "SHIB"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TAO"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "XRP"
|
||||
}
|
||||
list {
|
||||
key: "BinanceUsdsFutures"
|
||||
symbol: "1000PEPE"
|
||||
symbol: "1000SHIB"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "S"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TAO"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "XRP"
|
||||
}
|
||||
list {
|
||||
key: "OkxSpots"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BETH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "PEPE"
|
||||
symbol: "S"
|
||||
symbol: "SHIB"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "USDT"
|
||||
symbol: "XRP"
|
||||
}
|
||||
list {
|
||||
key: "OkxFutures"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "PEPE"
|
||||
symbol: "S"
|
||||
symbol: "SHIB"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TAO"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "XRP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Symbols {
|
||||
value {
|
||||
venues {
|
||||
name: "VENUE_BINANCE"
|
||||
spot: @SymbolLists.list[Binance].symbol
|
||||
}
|
||||
venues {
|
||||
name: "VENUE_BINANCE_USDS_FUTURES"
|
||||
future: @SymbolLists.list[BinanceUsdsFutures].symbol
|
||||
}
|
||||
venues {
|
||||
name: "VENUE_OKX"
|
||||
spot: @SymbolLists.list[OkxSpots].symbol
|
||||
future: @SymbolLists.list[OkxFutures].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -47,7 +47,7 @@ def _get_arg_parser():
|
||||
)
|
||||
# TODO: add more services (api-server, pubsub, dsqa web server, etc.)
|
||||
all_services = ["sparkd"]
|
||||
parser.add_argument("services", nargs="*")
|
||||
parser.add_argument("services", help="this selects services defined in compose.yaml", nargs="*")
|
||||
parser.set_defaults(
|
||||
configuration="release",
|
||||
services=all_services,
|
||||
@@ -70,7 +70,7 @@ def _get_env_files(services, profile):
|
||||
add(root.joinpath(".env"))
|
||||
add(root.joinpath(".env.local"))
|
||||
if profile is not None:
|
||||
if "sparkd" in services:
|
||||
if "sparkd" in services or "sparkd-symbols" in services:
|
||||
profile_dir=root.joinpath("src/server/sparkd/configurations", profile)
|
||||
add(profile_dir.joinpath(".env"))
|
||||
add(profile_dir.joinpath(".env.local"))
|
||||
|
||||
Reference in new issue
Block a user