Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added order volume limits #294

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/exchange-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ jobs:
run: cmake --install build --config Release --prefix .

- name: Move config file
run: cp -r config.yml build/test/config.yml
run: cp config.yml build/test/config.yml

- name: Move test algo files
run: cp -r -L test/src/integration/test_algos build/test/test_algos
Expand Down
47 changes: 23 additions & 24 deletions exchange/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ global:

order_fee: .0000
sandbox_trial_seconds: 300
max_cumulative_order_volume: 5000

tickers:
- ticker: "ETH"
Expand All @@ -20,28 +21,26 @@ tickers:
std_dev_capital: 2000

# perfect: 5/250000/5000, 25/1000/200
- ticker: "LTC"
start_price: 50
bots:
- type: "market_maker"
number_of_bots: 5
average_capital: 200000
std_dev_capital: 50000
- type: "retail"
number_of_bots: 25
average_capital: 5000
std_dev_capital: 2000

# - ticker: "LTC"
# start_price: 200
# bots:
# - type: "market_maker"
# number_of_bots: 10
# average_capital: 100000
# std_dev_capital: 25000
#
# - type: "retail"
# number_of_bots: 100
# average_capital: 7500
# std_dev_capital: 100
#
# - ticker: "BTC"
# start_price: 50
# bots:
# - type: "market_maker"
# number_of_bots: 10
# average_capital: 100000
# std_dev_capital: 10000
# - type: "retail"
# number_of_bots: 100
# average_capital: 2000
# std_dev_capital: 1000
- ticker: "BTC"
start_price: 200
bots:
- type: "market_maker"
number_of_bots: 25
average_capital: 200000
std_dev_capital: 50000
- type: "retail"
number_of_bots: 125
average_capital: 5000
std_dev_capital: 2000
28 changes: 14 additions & 14 deletions exchange/src/common/types/decimal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,56 @@

namespace nutc::common {

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>
Decimal<Scale>::operator-() const
{
return -value_;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
typename Decimal<Scale>::decimal_type
Decimal<Scale>::get_underlying() const
{
return value_;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
void
Decimal<Scale>::set_underlying(decimal_type value)
{
value_ = value;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>
Decimal<Scale>::operator-(const Decimal& other) const
{
return value_ - other.value_;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>
Decimal<Scale>::operator+(const Decimal& other) const
{
return value_ + other.value_;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>
Decimal<Scale>::operator/(const Decimal& other) const
{
return value_ * MULTIPLIER / other.value_;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>
Decimal<Scale>::operator*(const Decimal& other) const
{
return (value_ * other.value_) / MULTIPLIER;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>&
Decimal<Scale>::operator*=(const Decimal& other)
{
Expand All @@ -60,7 +60,7 @@ Decimal<Scale>::operator*=(const Decimal& other)
return *this;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>&
Decimal<Scale>::operator/=(const Decimal& other)
{
Expand All @@ -69,34 +69,34 @@ Decimal<Scale>::operator/=(const Decimal& other)
return *this;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>&
Decimal<Scale>::operator+=(const Decimal& other)
{
value_ += other.value_;
return *this;
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
bool
Decimal<Scale>::operator==(double other) const
{
return value_ == static_cast<decimal_type>(other * MULTIPLIER);
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>::operator double() const
{
return static_cast<double>(value_) / static_cast<double>(MULTIPLIER);
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>::operator float() const
{
return static_cast<float>(value_) / static_cast<float>(MULTIPLIER);
}

template <std::int8_t Scale>
template <std::uint8_t Scale>
Decimal<Scale>
Decimal<Scale>::difference(const Decimal& other) const
{
Expand Down
27 changes: 24 additions & 3 deletions exchange/src/common/types/decimal.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pow10(int pow)
}
} // namespace detail

template <std::int8_t Scale>
template <std::uint8_t Scale>
class Decimal {
using decimal_type = std::int64_t;
static constexpr std::int64_t MULTIPLIER = detail::pow10<decimal_type>(Scale);
Expand Down Expand Up @@ -88,6 +88,7 @@ class Decimal {
}

friend std::hash<Decimal<Scale>>;
friend std::numeric_limits<Decimal<Scale>>;
friend glz::meta<nutc::common::Decimal<Scale>>;
};

Expand All @@ -97,18 +98,38 @@ using decimal_quantity = Decimal<QUANTITY_DECIMAL_PLACES>;
} // namespace nutc::common

namespace std {
template <std::int8_t Scale>
template <std::uint8_t Scale>
struct hash<nutc::common::Decimal<Scale>> {
std::size_t
operator()(const nutc::common::Decimal<Scale>& obj) const
{
return std::hash<int64_t>{}(obj.value_);
}
};

// TODO: add unit tests
template <std::uint8_t Scale>
class numeric_limits<nutc::common::Decimal<Scale>> {
public:
static nutc::common::Decimal<Scale>
max()
{
return std::numeric_limits<
typename nutc::common::Decimal<Scale>::decimal_type>::max();
}

static nutc::common::Decimal<Scale>
min()
{
return std::numeric_limits<
typename nutc::common::Decimal<Scale>::decimal_type>::min();
}
};

} // namespace std

/// \cond
template <std::int8_t Scale>
template <std::uint8_t Scale>
struct glz::meta<nutc::common::Decimal<Scale>> {
using t = nutc::common::Decimal<Scale>;
static constexpr auto value = object(&t::value_);
Expand Down
8 changes: 7 additions & 1 deletion exchange/src/exchange/config/dynamic/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,22 @@ Config::get_global_config_(const YAML::Node& full_config)
const auto& wait_secs = global["wait_secs"];
const auto& sandbox_secs = global["sandbox_trial_seconds"];
const auto& order_fee = global["order_fee"];
const auto& max_order_volume = global["max_cumulative_order_volume"];

if (!starting_capital.IsDefined())
throw_undef_err("global/starting_capital");
if (!wait_secs.IsDefined())
throw_undef_err("global/wait_secs");
if (!sandbox_secs.IsDefined())
throw_undef_err("global/sandbox_trial_seconds");
if (!max_order_volume.IsDefined())
throw_undef_err("global/max_cumulative_order_volume");

return {
common::decimal_price(starting_capital.as<double>()), wait_secs.as<size_t>(),
sandbox_secs.as<unsigned int>(),
order_fee.IsDefined() ? order_fee.as<double>() : 0
order_fee.IsDefined() ? order_fee.as<double>() : 0,
common::decimal_quantity(max_order_volume.as<double>())
};
}

Expand Down
1 change: 1 addition & 0 deletions exchange/src/exchange/config/dynamic/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ struct global_config {
const size_t WAIT_SECS;
const unsigned int SANDBOX_TRIAL_SECS;
const double ORDER_FEE;
const common::decimal_quantity MAX_CUMULATIVE_OPEN_ORDER_VOLUME;
};

class Config {
Expand Down
13 changes: 10 additions & 3 deletions exchange/src/exchange/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,22 @@ create_cycle(TraderContainer& traders, const auto& mode)
const auto& ticker_config = Config::get().get_tickers();
double order_fee = Config::get().constants().ORDER_FEE;
auto tickers = TickerContainer(ticker_config, traders);
auto max_order_volume = Config::get().constants().MAX_CUMULATIVE_OPEN_ORDER_VOLUME;

switch (mode) {
case Mode::normal:
return std::make_unique<BaseMatchingCycle>(tickers, traders, order_fee);
return std::make_unique<BaseMatchingCycle>(
tickers, traders, order_fee, max_order_volume
);
case Mode::sandbox:
return std::make_unique<SandboxMatchingCycle>(tickers, traders, order_fee);
return std::make_unique<SandboxMatchingCycle>(
tickers, traders, order_fee, max_order_volume
);
case Mode::bots_only:
case Mode::dev:
return std::make_unique<DevMatchingCycle>(tickers, traders, order_fee);
return std::make_unique<DevMatchingCycle>(
tickers, traders, order_fee, max_order_volume
);
}

std::unreachable();
Expand Down
33 changes: 20 additions & 13 deletions exchange/src/exchange/matching_cycle/base/base_cycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,20 +55,27 @@ BaseMatchingCycle::match_orders_(std::vector<OrderVariant> orders)
{
std::vector<common::match> matches;

for (OrderVariant& order_variant : orders) {
auto match_incoming_order = [&]<typename OrderT>(OrderT& order) {
auto& ticker_data = tickers_[order.ticker];
auto& orderbook = ticker_data.get_orderbook();
if constexpr (std::is_same_v<OrderT, common::cancel_order>) {
orderbook.remove_order(order.order_id);
}
else {
if (order.quantity <= 0.0)
return;
auto tmp = match_order(order, orderbook, order_fee_);
std::copy(tmp.begin(), tmp.end(), std::back_inserter(matches));
auto match_incoming_order = [&]<typename OrderT>(OrderT& order) {
auto& ticker_data = tickers_[order.ticker];
auto& orderbook = ticker_data.get_orderbook();
if constexpr (std::is_same_v<OrderT, common::cancel_order>) {
orderbook.remove_order(order.order_id);
}
else {
if (order.quantity <= 0.0)
return;
// TODO: delegate elsewhere
if (order.quantity + order.trader->get_open_bids()
+ order.trader->get_open_asks()
> max_cumulative_order_volume_) {
return;
}
};
auto tmp = match_order(order, orderbook, order_fee_);
std::copy(tmp.begin(), tmp.end(), std::back_inserter(matches));
}
};

for (OrderVariant& order_variant : orders) {
std::visit(match_incoming_order, order_variant);
}
return matches;
Expand Down
8 changes: 6 additions & 2 deletions exchange/src/exchange/matching_cycle/base/base_cycle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ class BaseMatchingCycle : public MatchingCycleInterface {
TickerContainer tickers_;
TraderContainer& traders_;
common::decimal_price order_fee_;
common::decimal_quantity max_cumulative_order_volume_;

public:
// Require transfer of ownership
BaseMatchingCycle(
TickerContainer tickers, TraderContainer& traders, common::decimal_price order_fee
) : tickers_(std::move(tickers)), traders_(traders), order_fee_(order_fee)
TickerContainer tickers, TraderContainer& traders,
common::decimal_price order_fee, common::decimal_quantity max_order_volume
) :
tickers_(std::move(tickers)), traders_(traders), order_fee_(order_fee),
max_cumulative_order_volume_{max_order_volume}
{}

protected:
Expand Down
8 changes: 6 additions & 2 deletions exchange/src/exchange/matching_cycle/dev/dev_cycle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ class DevMatchingCycle : public BaseMatchingCycle {
TickerMetricsPusher pusher;

public:
DevMatchingCycle(TickerContainer tickers, TraderContainer& traders, common::decimal_price order_fee) :
BaseMatchingCycle(std::move(tickers), traders, order_fee), pusher(traders)
DevMatchingCycle(
TickerContainer tickers, TraderContainer& traders,
common::decimal_price order_fee, common::decimal_quantity max_order_volume
) :
BaseMatchingCycle(std::move(tickers), traders, order_fee, max_order_volume),
pusher(traders)
{}

protected:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace nutc::exchange {

class SandboxMatchingCycle : public DevMatchingCycle {
public:
SandboxMatchingCycle(TickerContainer tickers, TraderContainer& traders, common::decimal_price order_fee) :
DevMatchingCycle(std::move(tickers), traders, order_fee)
SandboxMatchingCycle(TickerContainer tickers, TraderContainer& traders, common::decimal_price order_fee, common::decimal_quantity max_order_volume) :
DevMatchingCycle(std::move(tickers), traders, order_fee, max_order_volume)
{}

private:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "common/types/decimal.hpp"
#include "common/util.hpp"
#include "exchange/config/dynamic/config.hpp"
#include "exchange/orders/storage/order_storage.hpp"

namespace nutc::exchange {
Expand Down
Loading
Loading