Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e974edfc6e | ||
|
|
3b7740cee0 | ||
|
|
258d4a3fc1 | ||
|
|
c53f6425cd |
No files matched your search
+1
-1
Submodule docker/linux updated: 6f0dd9324b...7258a028d7.
+28
-3
@@ -60,10 +60,13 @@ class IntPrice {
|
||||
return delta.mantissa() < 0;
|
||||
}
|
||||
}
|
||||
bool operator <=(const IntPrice& other) {
|
||||
bool operator <=(const IntPrice& other) const {
|
||||
return *this == other || *this < other;
|
||||
}
|
||||
bool operator >=(const IntPrice& other) {
|
||||
bool operator >(const IntPrice& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
bool operator >=(const IntPrice& other) const {
|
||||
return !(*this < other);
|
||||
}
|
||||
IntPrice operator - (const IntPrice& o) const {
|
||||
@@ -72,9 +75,31 @@ class IntPrice {
|
||||
IntPrice operator + (const IntPrice& o) const {
|
||||
return op(o, [](int64_t m1, int64_t m2) { return m1 + m2; });
|
||||
}
|
||||
IntPrice& operator +=(const IntPrice& o) {
|
||||
auto temp = *this + o;
|
||||
_mantissa = temp._mantissa;
|
||||
_exponent = temp._exponent;
|
||||
return *this;
|
||||
}
|
||||
IntPrice& operator -=(const IntPrice& o) {
|
||||
auto temp = *this - o;
|
||||
_mantissa = temp._mantissa;
|
||||
_exponent = temp._exponent;
|
||||
return *this;
|
||||
}
|
||||
IntPrice operator -() {
|
||||
return IntPrice(-_mantissa, _exponent);
|
||||
}
|
||||
IntPrice operator * (const IntPrice& other) const {
|
||||
return op(other, [](int64_t m1, int64_t m2) { return m1 * m2; });
|
||||
}
|
||||
IntPrice operator * (const int& other) const {
|
||||
return IntPrice(_mantissa * other, _exponent);
|
||||
}
|
||||
IntPrice& operator *=(const int& other) {
|
||||
_mantissa *= other;
|
||||
return *this;
|
||||
}
|
||||
IntPrice operator / (double v) const {
|
||||
return { (int64_t)(_mantissa / v), exponent() };
|
||||
}
|
||||
@@ -183,4 +208,4 @@ inline std::ostream& operator<<(std::ostream& os, const IntPrice& p) {
|
||||
return os;
|
||||
}
|
||||
|
||||
}}
|
||||
}}
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "BookUtils.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
using Size = bts::md::Size;
|
||||
using Side = bts::api::Side;
|
||||
namespace bts::orderman {
|
||||
using Size = md::Size;
|
||||
using Side = api::Side;
|
||||
using PriceSize = md::PriceSize;
|
||||
|
||||
Size BookUtils::volume_at_or_better(const Book& book, Side side, Price price) {
|
||||
return volume_at_or_better(book, side, price.value());
|
||||
@@ -22,5 +22,154 @@ Size BookUtils::volume_at_or_better(const Book& book, Side side, double price) {
|
||||
SidePriceComp BookUtils::price_comp(Side side) {
|
||||
return SidePriceComp(side);
|
||||
}
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
|
||||
inline bool is_empty(const PriceSize& ps) {
|
||||
return ps.size() == 0 || ps.int_price().is_nan();
|
||||
}
|
||||
|
||||
void BookUtils::change_unit_qty(
|
||||
const BookSide& book_in, std::vector<md::PriceSize>& book_out, int unit_qty) {
|
||||
//
|
||||
bts_assert(unit_qty > 0);
|
||||
int mlev = 0, mlev_qty_used = 0;
|
||||
std::vector<md::PriceSize> unit_lev_span;
|
||||
for (uint32_t i = 0; i < book_in.size();) {
|
||||
int mlev_qty_rem = book_in[i].size() - mlev_qty_used;
|
||||
if (mlev_qty_rem == 0) {
|
||||
mlev_qty_used = 0;
|
||||
mlev++;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (unit_lev_span.size() == 0) {
|
||||
md::Size mlev_units_rem = mlev_qty_rem / unit_qty;
|
||||
if (mlev_units_rem > 0) {
|
||||
book_out.emplace_back(book_in[i].int_price(), mlev_units_rem);
|
||||
mlev_qty_used += mlev_units_rem * unit_qty;
|
||||
} else {
|
||||
unit_lev_span.emplace_back(book_in[i].int_price(), mlev_qty_rem);
|
||||
mlev_qty_used = 0;
|
||||
mlev++;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
// the unit spans across multiple [input]price levels: compute its
|
||||
// [output]price. It will be in its own [output]price level.
|
||||
auto unit_rem = unit_qty;
|
||||
for (auto lev : unit_lev_span)
|
||||
unit_rem -= lev.size();
|
||||
if (mlev_qty_rem >= unit_rem) {
|
||||
mlev_qty_used += unit_rem;
|
||||
auto unit_price = md::INT_NAN;
|
||||
for (uint32_t adj_lev = 0; adj_lev < unit_lev_span.size(); adj_lev++) {
|
||||
auto leg_price = unit_lev_span[adj_lev].int_price() *
|
||||
static_cast<int>(unit_lev_span[adj_lev].size());
|
||||
if (unit_price.is_nan())
|
||||
unit_price = leg_price;
|
||||
else
|
||||
unit_price += leg_price;
|
||||
}
|
||||
unit_lev_span.clear();
|
||||
book_out.emplace_back(unit_price, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BookUtils::compute_synthetic_book(
|
||||
std::vector<PriceSize>& dest,
|
||||
const std::vector<std::tuple<Size, md::IntPrice, BookSide>>&
|
||||
leg_mkts,
|
||||
uint32_t depth) {
|
||||
//
|
||||
if (leg_mkts.size() == 0)
|
||||
return;
|
||||
|
||||
struct Leg {
|
||||
std::vector<PriceSize> book;
|
||||
uint32_t curr_level;
|
||||
Size curr_level_qty_used;
|
||||
int leg_qty;
|
||||
|
||||
Leg() : book(), curr_level(0), curr_level_qty_used(0), leg_qty(0) {}
|
||||
|
||||
md::IntPrice curr_price() const {
|
||||
// Assert that the book isn't 'empty' yet.
|
||||
// Note: one could argue that nan be returned in this event,
|
||||
// but since the loop is designed to return "greedily,"
|
||||
// 'curr_price' should not be accessed after it has been emptied.
|
||||
// This assertion enforces that the behavior is only changed
|
||||
// as a result of deliberate action, rather than an inadvertant
|
||||
// side-effect.
|
||||
bts_assert(!is_empty());
|
||||
return book[curr_level].int_price();
|
||||
}
|
||||
Size curr_level_qty_rem() const {
|
||||
return book[curr_level].size() - curr_level_qty_used;
|
||||
}
|
||||
// The implied market's volume is limited by its thinnest market.
|
||||
// When one leg 'is_empty,' the full volume of the implied market
|
||||
// has been realized.
|
||||
bool is_empty() const { return curr_level >= book.size(); }
|
||||
};
|
||||
|
||||
std::vector<Leg> legs;
|
||||
for (const auto& [qty, price_mult, book] : leg_mkts) {
|
||||
// todo: implement price mult logic (for now just assert nan or 1)
|
||||
bts_assert(price_mult.is_nan() || price_mult.price() == 1);
|
||||
auto& l = legs.emplace_back();
|
||||
bts_assert(qty != 0);
|
||||
l.leg_qty = qty;
|
||||
if (book.empty() || is_empty(book.front()))
|
||||
return;
|
||||
change_unit_qty(
|
||||
book, l.book, std::abs(l.leg_qty));
|
||||
if (l.book.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
auto any_legs_empty = [&]() {
|
||||
for (auto& l : legs)
|
||||
if (l.is_empty())
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
while (!any_legs_empty() && depth-- > 0) {
|
||||
// legs can't be empty, because it is a 1:1 mapping of leg_mkts,
|
||||
// and it has already been established that the latter isn't empty.
|
||||
auto limiting_factor = legs[0].curr_level_qty_rem();
|
||||
for (uint32_t i = 0; i < legs.size(); i++) {
|
||||
if (legs[i].curr_level_qty_rem() == 0) {
|
||||
legs[i].curr_level++;
|
||||
if (legs[i].is_empty()) {
|
||||
// book is complete
|
||||
return;
|
||||
}
|
||||
legs[i].curr_level_qty_used = Size(0);
|
||||
}
|
||||
limiting_factor =
|
||||
std::min(legs[i].curr_level_qty_rem(), limiting_factor);
|
||||
if (limiting_factor == 0)
|
||||
return;
|
||||
}
|
||||
bts_assert(limiting_factor > 0);
|
||||
for (uint32_t i = 0; i < legs.size(); i++)
|
||||
legs[i].curr_level_qty_used += limiting_factor;
|
||||
auto marginal_cost = md::INT_NAN;
|
||||
for (auto& l : legs) {
|
||||
// The book's prices have already been multiplied by abs(leg_qty);
|
||||
// Subtract the leg's cost if qty is negative, otherwise add it
|
||||
// to the synthetic's marginal cost.
|
||||
auto lcost = l.curr_price();
|
||||
if (l.leg_qty < 0)
|
||||
lcost = -lcost;
|
||||
if (marginal_cost.is_nan())
|
||||
marginal_cost = lcost;
|
||||
else
|
||||
marginal_cost += lcost;
|
||||
}
|
||||
dest.emplace_back(marginal_cost, limiting_factor);
|
||||
}
|
||||
}
|
||||
} // namespace bts::orderman
|
||||
@@ -6,13 +6,18 @@
|
||||
#include "lib/orderman/orderman_utils/Book.h"
|
||||
#include "lib/orderman/orderman_utils/PriceComp.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
|
||||
namespace bts::orderman {
|
||||
struct BookUtils {
|
||||
static md::Size volume_at_or_better(const Book& book, api::Side side, Price price);
|
||||
static md::Size volume_at_or_better(const Book& book, api::Side side, double price);
|
||||
static SidePriceComp price_comp(api::Side side);
|
||||
|
||||
static void change_unit_qty(
|
||||
const BookSide& book_in, std::vector<md::PriceSize>& book_out, int unit_qty);
|
||||
|
||||
static void compute_synthetic_book(
|
||||
std::vector<md::PriceSize>& dest,
|
||||
const std::vector<std::tuple<md::Size, md::IntPrice, BookSide>>& leg_mkts,
|
||||
uint32_t depth);
|
||||
};
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
} // namespace bts::orderman
|
||||
Reference in new issue
Block a user