Skip to content

Commit

Permalink
Parameterize cancellation integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenewald committed Sep 20, 2024
1 parent e260bc0 commit 0bb5ec7
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 34 deletions.
2 changes: 2 additions & 0 deletions exchange/src/common/types/algorithm/algorithm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "local_algorithm.hpp"
#include "remote_algorithm.hpp"

#include <variant>

namespace nutc::common {
using algorithm_variant = std::variant<RemoteAlgorithm, LocalAlgorithm>;

Expand Down
11 changes: 8 additions & 3 deletions exchange/src/common/types/algorithm/local_algorithm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
#include "base_algorithm.hpp"
#include "common/file_operations/file_operations.hpp"

#include <boost/filesystem.hpp>

#include <cassert>

#include <filesystem>
#include <optional>

namespace nutc::common {
Expand All @@ -13,9 +16,11 @@ LocalAlgorithm::compile_cpp_() const
{
assert(get_language() == AlgoLanguage::cpp);
static constexpr std::string_view TEMPLATE_PATH = "test_algos/cpp/template.cpp";
std::string output_path = fmt::format("/tmp/algo_cpp_path.so", filepath_.string());
std::string binary_output = (boost::filesystem::temp_directory_path()
/ boost::filesystem::unique_path("%%%%-%%%%-%%%%.tmp"))
.string();
std::string command = fmt::format(
"g++ -std=c++20 -fPIC -shared -o {} -include {} {}", output_path,
"g++ -std=c++20 -fPIC -shared -o {} -include {} {}", binary_output,
filepath_.string(), TEMPLATE_PATH
);

Expand All @@ -26,7 +31,7 @@ LocalAlgorithm::compile_cpp_() const
fmt::format("Compilation of {} failed", filepath_.string())
);
}
return output_path;
return binary_output;
}

LocalAlgorithm::LocalAlgorithm(AlgoLanguage language, std::filesystem::path filepath) :
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <cstdint>

#include <string>

/**
* Place a market order
*
* IMPORTANT:
* You should handle the case where the order fails due to rate limiting
* (maybe wait and try again?)
*
* @param side Side of the order to place ("BUY" or "SELL")
* @param ticker Ticker of the order to place ("ETH", "BTC", or "LTC")
* @param quantity Volume of the order to place
*
* @return true if order succeeded, false if order failed due to rate limiting
*/
bool
place_market_order(std::string const& side, std::string const& ticker, double quantity);

/**
* Place a limit order
*
* IMPORTANT:
* You should handle the case where the order fails due to rate limiting
* (maybe wait and try again?)
*
* @param side Side of the order to place ("BUY" or "SELL")
* @param ticker Ticker of the order to place ("ETH", "BTC", or "LTC")
* @param quantity Volume of the order to place
* @param price Price of the order to place
* @param ioc Immediate or cancel
*
* @return true if order succeeded, false if order failed due to rate limiting
*/
std::int64_t place_limit_order(
std::string const& side, std::string const& ticker, double quantity, double price,
bool ioc = false
);

bool cancel_order(std::string const& ticker, std::int64_t order_id);

class Strategy {
public:
Strategy()
{
auto order_id = place_limit_order("BUY", "ETH", 100, 10);
cancel_order("ETH", order_id);
}

/**
* Called whenever two orders match. Could be one of your orders, or two other
* people's orders.
*
* @param ticker Ticker of the orders that were matched ("ETH", "BTC", or
* "LTC)
* @param side Side of the orders that were matched ("BUY" or "SELL")
* @param price Price that trade was executed at
* @quantity quantity Volume traded
*/
void
on_trade_update(std::string ticker, std::string side, double quantity, double price)
{}

/**
* Called whenever the orderbook changes. This could be because of a trade, or
* because of a new order, or both.
*
* @param ticker Ticker that has an orderbook update ("ETH", "BTC", or "LTC")
* @param side Which orderbook as updated ("BUY" or "SELL")
* @param price Price of orderbook that has an update
* @param quantity Volume placed into orderbook
*/
void
on_orderbook_update(
std::string ticker, std::string side, double quantity, double price
)
{}

/**
* Called whenever one of your orders is filled.
*
* @param ticker Ticker of order that was fulfilled ("ETH", "BTC", or "LTC")
* @param side Side of order that was fulfilled ("BUY" or "SELL")
* @param price Price that order was fulfilled at
* @param quantity Amount of capital after fulfilling order
*/
void
on_account_update(
std::string ticker, std::string side, double price, double quantity,
double capital_remaining
)
{}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include <cstdint>

#include <string>

/**
* Place a market order
*
* IMPORTANT:
* You should handle the case where the order fails due to rate limiting
* (maybe wait and try again?)
*
* @param side Side of the order to place ("BUY" or "SELL")
* @param ticker Ticker of the order to place ("ETH", "BTC", or "LTC")
* @param quantity Volume of the order to place
*
* @return true if order succeeded, false if order failed due to rate limiting
*/
bool
place_market_order(std::string const& side, std::string const& ticker, double quantity);

/**
* Place a limit order
*
* IMPORTANT:
* You should handle the case where the order fails due to rate limiting
* (maybe wait and try again?)
*
* @param side Side of the order to place ("BUY" or "SELL")
* @param ticker Ticker of the order to place ("ETH", "BTC", or "LTC")
* @param quantity Volume of the order to place
* @param price Price of the order to place
* @param ioc Immediate or cancel
*
* @return true if order succeeded, false if order failed due to rate limiting
*/
std::int64_t place_limit_order(
std::string const& side, std::string const& ticker, double quantity, double price,
bool ioc = false
);

bool cancel_order(std::string const& ticker, std::int64_t order_id);

class Strategy {
public:
Strategy()
{
auto order_id = place_limit_order("BUY", "ETH", 100, 10);
place_limit_order("BUY", "ETH", 100, 20);
cancel_order("ETH", order_id);
}

/**
* Called whenever two orders match. Could be one of your orders, or two other
* people's orders.
*
* @param ticker Ticker of the orders that were matched ("ETH", "BTC", or
* "LTC)
* @param side Side of the orders that were matched ("BUY" or "SELL")
* @param price Price that trade was executed at
* @quantity quantity Volume traded
*/
void
on_trade_update(std::string ticker, std::string side, double quantity, double price)
{}

/**
* Called whenever the orderbook changes. This could be because of a trade, or
* because of a new order, or both.
*
* @param ticker Ticker that has an orderbook update ("ETH", "BTC", or "LTC")
* @param side Which orderbook as updated ("BUY" or "SELL")
* @param price Price of orderbook that has an update
* @param quantity Volume placed into orderbook
*/
void
on_orderbook_update(
std::string ticker, std::string side, double quantity, double price
)
{}

/**
* Called whenever one of your orders is filled.
*
* @param ticker Ticker of order that was fulfilled ("ETH", "BTC", or "LTC")
* @param side Side of order that was fulfilled ("BUY" or "SELL")
* @param price Price that order was fulfilled at
* @param quantity Amount of capital after fulfilling order
*/
void
on_account_update(
std::string ticker, std::string side, double price, double quantity,
double capital_remaining
)
{}
};
20 changes: 0 additions & 20 deletions exchange/test/src/integration/tests/basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,6 @@

#include <gtest/gtest.h>

namespace nutc::common {
void
PrintTo(const AlgoLanguage& op, std::ostream* os)
{
switch (op) {
case AlgoLanguage::cpp:
*os << "CPP";
break;
case AlgoLanguage::python:
*os << "PYTHON";
break;
default:
*os << "UNKNOWN_LANGUAGE";
break;
}
}
} // namespace nutc::common

namespace nutc::test {
using common::limit_order;
using nutc::common::AlgoLanguage;
Expand Down Expand Up @@ -125,7 +107,6 @@ TEST_P(IntegrationBasicAlgo, MarketOrderSell)
cycle.wait_for_order(limit_order{Ticker::BTC, buy, 1.0, 100.0});
}


TEST_P(IntegrationBasicAlgo, ManyUpdates)
{
start_wrappers(traders_, GetParam(), "confirm_1000");
Expand Down Expand Up @@ -256,7 +237,6 @@ TEST_P(IntegrationBasicAlgo, DisableTrader)
ASSERT_TRUE(orders.empty());
}


INSTANTIATE_TEST_SUITE_P(
IntegrationBasic, IntegrationBasicAlgo,
::testing::Values(AlgoLanguage::python, AlgoLanguage::cpp)
Expand Down
21 changes: 12 additions & 9 deletions exchange/test/src/integration/tests/cancellation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,27 @@
namespace nutc::test {
using nutc::common::AlgoLanguage;

class IntegrationBasicCancellation : public ::testing::Test {
class IntegrationBasicCancellation : public ::testing::TestWithParam<AlgoLanguage> {
protected:
using Ticker = nutc::common::Ticker;
using nutc::common::Side::buy;
using nutc::common::Side::sell;
exchange::TraderContainer traders_;
};

TEST_F(IntegrationBasicCancellation, CancelMessageHasSameIdAsOrder)
TEST_P(IntegrationBasicCancellation, CancelMessageHasSameIdAsOrder)
{
start_wrappers(traders_, AlgoLanguage::python, "cancel_limit_order");
start_wrappers(traders_, GetParam(), "cancel_limit_order");
TestMatchingCycle cycle{traders_};

auto order_id = cycle.wait_for_order(limit_order{Ticker::ETH, buy, 100.0, 10.0});
EXPECT_TRUE(order_id.has_value());
cycle.wait_for_order(common::cancel_order{common::Ticker::ETH, *order_id});
}

TEST_F(IntegrationBasicCancellation, CancelMessagePreventsOrderFromExecuting)
TEST_P(IntegrationBasicCancellation, CancelMessagePreventsOrderFromExecuting)
{
auto& trader1 =
start_wrappers(traders_, AlgoLanguage::python, "cancel_limit_order");
auto& trader1 = start_wrappers(traders_, GetParam(), "cancel_limit_order");
auto trader2 = traders_.add_trader<TestTrader>(0);
trader2->modify_holdings(Ticker::ETH, 100.0);
TestMatchingCycle cycle{traders_};
Expand All @@ -48,10 +47,9 @@ TEST_F(IntegrationBasicCancellation, CancelMessagePreventsOrderFromExecuting)
EXPECT_EQ(trader1.get_holdings(Ticker::ETH), 0);
}

TEST_F(IntegrationBasicCancellation, OneOfTwoOrdersCancelledResultsInMatch)
TEST_P(IntegrationBasicCancellation, OneOfTwoOrdersCancelledResultsInMatch)
{
auto& trader1 =
start_wrappers(traders_, AlgoLanguage::python, "partial_cancel_limit_order");
auto& trader1 = start_wrappers(traders_, GetParam(), "partial_cancel_limit_order");
auto trader2 = traders_.add_trader<TestTrader>(0);
trader2->modify_holdings(Ticker::ETH, 100.0);
TestMatchingCycle cycle{traders_};
Expand All @@ -68,4 +66,9 @@ TEST_F(IntegrationBasicCancellation, OneOfTwoOrdersCancelledResultsInMatch)
EXPECT_EQ(double{trader2->get_capital_delta()}, 200);
EXPECT_EQ(double{trader1.get_holdings(Ticker::ETH)}, 10);
}

INSTANTIATE_TEST_SUITE_P(
IntegrationBasicCancellation, IntegrationBasicCancellation,
::testing::Values(AlgoLanguage::python, AlgoLanguage::cpp)
);
} // namespace nutc::test
22 changes: 20 additions & 2 deletions exchange/test/src/util/macros.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "common/messages_exchange_to_wrapper.hpp"
#include "common/messages_wrapper_to_exchange.hpp"
#include "common/types/algorithm/base_algorithm.hpp"
#include "common/types/ticker.hpp"
#include "exchange/orders/storage/order_storage.hpp"
#include "exchange/traders/trader_container.hpp"
Expand All @@ -9,6 +10,24 @@ using tagged_limit_order = nutc::exchange::tagged_limit_order;
using tagged_market_order = nutc::exchange::tagged_market_order;
using TraderContainer = nutc::exchange::TraderContainer;

namespace nutc::common {
inline void
PrintTo(const AlgoLanguage& op, std::ostream* os)
{
switch (op) {
case AlgoLanguage::cpp:
*os << "CPP";
break;
case AlgoLanguage::python:
*os << "PYTHON";
break;
default:
*os << "UNKNOWN_LANGUAGE";
break;
}
}
} // namespace nutc::common

namespace nutc::test {

bool validate_match(
Expand Down Expand Up @@ -84,8 +103,7 @@ order_equality(const common::market_order& order1, const common::market_order& o
<< "Expected market order with" \
<< " ticker =" << (nutc::common::to_string(ticker_)) \
<< ", side = " << static_cast<int>(side_) << ", price = " << (price_) \
<< ", quantity = " << (quantity_) << ". Actual update: client_id = " \
<< "" \
<< ", quantity = " << (quantity_) << ". Actual update: client_id = " << "" \
<< ", ticker = " << nutc::common::to_string((update).ticker) \
<< ", side = " << static_cast<int>((update).side) \
<< ", price = " << double((update).price) \
Expand Down

0 comments on commit 0bb5ec7

Please sign in to comment.