Skip to content

Commit

Permalink
Live auto trade mode
Browse files Browse the repository at this point in the history
  • Loading branch information
sjanel committed Feb 9, 2025
1 parent 9fbd88e commit 32634ca
Show file tree
Hide file tree
Showing 19 changed files with 636 additions and 15 deletions.
63 changes: 63 additions & 0 deletions data/static/auto-trade-example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{
"kraken": {
"BTC-EUR": {
"accounts": [
"user1",
"user2"
],
"algorithmName": "example-trader",
"repeatTime": "5s",
"baseStartAmount": "0.5BTC",
"quoteStartAmount": "50%EUR",
"stopCriteria": [
{
"type": "duration",
"value": "4h"
},
{
"type": "protectLoss",
"value": "-30%"
},
{
"type": "secureProfit",
"value": "80%"
}
]
},
"ETH-EUR": {
"accounts": [
"user1"
],
"algorithmName": "example-trader",
"repeatTime": "3s",
"baseStartAmount": "45ETH",
"quoteStartAmount": "50%EUR",
"stopCriteria": [
{
"type": "duration",
"value": "4h"
},
{
"type": "protectLoss",
"value": "-30%"
},
{
"type": "secureProfit",
"value": "80%"
}
]
}
},
"binance": {
"XRP-USDT": {
"accounts": [
"user1"
],
"algorithmName": "example-trader",
"repeatTime": "1s",
"baseStartAmount": "50000.56XRP",
"quoteStartAmount": "100%USDT",
"stopCriteria": []
}
}
}
4 changes: 2 additions & 2 deletions src/basic-objects/include/coincentercommandtype.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace cct {
Balance, DepositInfo, OrdersClosed, OrdersOpened, OrdersCancel, RecentDeposits, RecentWithdraws, Trade, Buy, \
Sell, Withdraw, DustSweeper, \
\
MarketData, Replay, ReplayMarkets
MarketData, Replay, ReplayMarkets, AutoTrade

enum class CoincenterCommandType : int8_t { CCT_COINCENTER_COMMAND_TYPES };

Expand All @@ -27,4 +27,4 @@ struct glz::meta<::cct::CoincenterCommandType> {
static constexpr auto value = enumerate(CCT_COINCENTER_COMMAND_TYPES);
};

#undef CCT_COINCENTER_COMMAND_TYPES
#undef CCT_COINCENTER_COMMAND_TYPES
58 changes: 58 additions & 0 deletions src/engine/include/auto-trade-options.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#pragma once

#include <map>

#include "auto-trade-config.hpp"
#include "cct_fixedcapacityvector.hpp"
#include "cct_smallvector.hpp"
#include "cct_vector.hpp"
#include "exchange-name-enum.hpp"
#include "exchange-names.hpp"
#include "exchangename.hpp"

namespace cct {

class AutoTradeOptions {
public:
using AccountAutoTradeOptionsPtrVector =
SmallVector<const schema::AutoTradeExchangeConfig *, kTypicalNbPrivateAccounts>;

struct MarketExchanges {
Market market;
ExchangeNames privateExchangeNames;
const schema::AutoTradeMarketConfig *pMarketAutoTradeOptions{};
};

using MarketStatusVector = vector<MarketExchanges>;

struct MarketExchangeOptions {
MarketStatusVector marketStatusVector;
};

struct PublicExchangeMarketOptions {
ExchangeName publicExchangeName;
MarketExchangeOptions marketExchangeOptions;
};

using PublicExchangeMarketOptionsVector = FixedCapacityVector<schema::AutoTradeExchangeConfig, kNbSupportedExchanges>;

AutoTradeOptions() noexcept = default;

explicit AutoTradeOptions(schema::AutoTradeConfig &&autoTradeConfig);

auto begin() const { return _autoTradeConfig.begin(); }
auto end() const { return _autoTradeConfig.end(); }

ExchangeNames exchangeNames() const;

ExchangeNameEnumVector publicExchanges() const;

AccountAutoTradeOptionsPtrVector accountAutoTradeOptionsPtr(std::string_view publicExchangeName) const;

const schema::AutoTradeExchangeConfig &operator[](ExchangeNameEnum exchangeNameEnum) const;

private:
schema::AutoTradeConfig _autoTradeConfig;
};

} // namespace cct
60 changes: 60 additions & 0 deletions src/engine/include/auto-trade-processor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#pragma once

#include <array>
#include <compare>
#include <functional>
#include <unordered_map>

#include "auto-trade-config.hpp"
#include "cct_smallvector.hpp"
#include "cct_vector.hpp"
#include "exchange-names.hpp"
#include "exchange.hpp"
#include "market-trader-engine.hpp"
#include "market.hpp"
#include "timedef.hpp"

namespace cct {
class AutoTradeOptions;
class CoincenterInfo;

class AutoTradeProcessor {
public:
using MarketTraderEngines = std::array<std::unordered_map<Market, MarketTraderEngine>, kNbSupportedExchanges>;

explicit AutoTradeProcessor(const AutoTradeOptions& autoTradeOptions);

struct SelectedMarket {
ExchangeNames privateExchangeNames;
Market market;
};

using SelectedMarketVector = SmallVector<SelectedMarket, kTypicalNbPrivateAccounts>;

SelectedMarketVector computeSelectedMarkets();

MarketTraderEngines createMarketTraderEngines(const CoincenterInfo& coincenterInfo) const;

private:
struct MarketStatus {
ExchangeNames privateExchangeNames;
Market market;
TimePoint lastQueryTime;
const schema::AutoTradeMarketConfig* pMarketAutoTradeOptions{};
};

using MarketStatusVector = vector<MarketStatus>;

struct ExchangeStatus {
MarketStatusVector marketStatusVector;
const schema::AutoTradeExchangeConfig* pPublicExchangeAutoTradeOptions{};
ExchangeNameEnum exchangeNameEnum;
};

using ExchangeStatusVector = SmallVector<ExchangeStatus, kTypicalNbPrivateAccounts>;

ExchangeStatusVector _exchangeStatusVector;
TimePoint _startTs = Clock::now();
TimePoint _ts{_startTs};
};
} // namespace cct
8 changes: 6 additions & 2 deletions src/engine/include/coincenter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <span>

#include "apikeysprovider.hpp"
#include "auto-trade-options.hpp"
#include "cct_fixedcapacityvector.hpp"
#include "coincenterinfo.hpp"
#include "commonapi.hpp"
Expand Down Expand Up @@ -149,6 +150,9 @@ class Coincenter {
ReplayResults replay(const AbstractMarketTraderFactory &marketTraderFactory, const ReplayOptions &replayOptions,
Market market, ExchangeNameSpan exchangeNames);

/// Run auto trade.
void autoTrade(const AutoTradeOptions &autoTradeOptions);

/// Dumps the content of all file caches in data directory to save cURL queries.
void updateFileCaches() const;

Expand All @@ -173,8 +177,8 @@ class Coincenter {
const ExchangeNameEnumVector &exchangesWithThisMarketData);

// TODO: may be moved somewhere else?
MarketTraderEngineVector createMarketTraderEngines(const ReplayOptions &replayOptions, Market market,
ExchangeNameEnumVector &exchangesWithThisMarketData);
MarketTraderEngineVector createMarketTraderEnginesForReplay(const ReplayOptions &replayOptions, Market market,
ExchangeNameEnumVector &exchangesWithThisMarketData);

MarketTradeRangeStatsPerExchange tradingProcess(const ReplayOptions &replayOptions,
std::span<MarketTraderEngine> marketTraderEngines,
Expand Down
7 changes: 6 additions & 1 deletion src/engine/include/coincentercommand.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstdint>
#include <optional>
#include <string_view>
#include <type_traits>
#include <variant>

Expand Down Expand Up @@ -47,6 +48,8 @@ class CoincenterCommand {

CoincenterCommand& setReplayOptions(ReplayOptions replayOptions);

CoincenterCommand& setJsonConfigFile(std::string_view jsonConfigFile);

CoincenterCommand& setPercentageAmount(bool value = true);
CoincenterCommand& withBalanceInUse(bool value = true);

Expand Down Expand Up @@ -79,6 +82,8 @@ class CoincenterCommand {

const ReplayOptions& replayOptions() const { return std::get<ReplayOptions>(_specialOptions); }

std::string_view getJsonConfigFile() const { return std::get<std::string_view>(_specialOptions); }

bool operator==(const CoincenterCommand&) const noexcept = default;

using trivially_relocatable =
Expand All @@ -89,7 +94,7 @@ class CoincenterCommand {

private:
using SpecialOptions = std::variant<std::monostate, OrdersConstraints, WithdrawsOrDepositsConstraints, TradeOptions,
WithdrawOptions, ReplayOptions>;
WithdrawOptions, ReplayOptions, std::string_view>;

ExchangeNames _exchangeNames;
SpecialOptions _specialOptions;
Expand Down
2 changes: 2 additions & 0 deletions src/engine/include/coincenteroptions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ class CoincenterCmdLineOptions {

std::string_view marketData;

std::string_view autoTrade;

std::optional<std::string_view> replay;
std::string_view algorithmNames;
std::string_view market;
Expand Down
16 changes: 16 additions & 0 deletions src/engine/include/coincenteroptionsdef.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,22 @@ struct CoincenterAllowedOptions : private CoincenterCmdLineOptionsDefinitions {
"\nNominal replay will not validate input data to optimize performance, use this option to validate data once "
"and for all."},
&OptValueType::validateOnly},
{{{"Automation", 8004},
"auto-trade",
"<path/to/json.conf>",
"Automatic live trading mode. Once you have validated on historical market-data the performance of an "
"algorithm, it's time to try it for real!\n"
"This command has some particularities:\n"
"- next commands will never be executed\n"
"- repeat is ignored (the auto trade will continue until one of terminating signals defined in the "
"configuration file is reached)\n"
"Configuration will be loaded from given json file, with following options (check README to get full "
"configuration schema):\n"
"- 'algorithm' : algorithm name to use\n"
"- 'market' : the market to trade onto\n"
"- 'startAmount' : the starting amount in base currency (can be a percentage of available amount)\n"
"- 'exchange' : exchange with account key (not needed if not ambiguous)"},
&OptValueType::autoTrade},
{{{"Monitoring", 9000},
"--monitoring",
"",
Expand Down
2 changes: 2 additions & 0 deletions src/engine/include/exchangesorchestrator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include <optional>
#include <span>

#include "auto-trade-options.hpp"
#include "auto-trade-processor.hpp"
#include "exchange-name-enum.hpp"
#include "exchange-names.hpp"
#include "exchangename.hpp"
Expand Down
63 changes: 63 additions & 0 deletions src/engine/src/auto-trade-options.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include "auto-trade-options.hpp"

#include <utility>

#include "auto-trade-config.hpp"
#include "cct_invalid_argument_exception.hpp"

namespace cct {

AutoTradeOptions::AutoTradeOptions(schema::AutoTradeConfig &&autoTradeConfig)
: _autoTradeConfig(std::move(autoTradeConfig)) {}

ExchangeNames AutoTradeOptions::exchangeNames() const {
ExchangeNames exchangeNames;
for (const auto &[exchangeNameEnum, publicExchangeAutoTradeOptions] : _autoTradeConfig) {
const int posPublicExchangeName = exchangeNames.size();
for (const auto &[market, autoTradeMarketConfig] : publicExchangeAutoTradeOptions) {
const int posMarket = exchangeNames.size();
for (std::string_view account : autoTradeMarketConfig.accounts) {
ExchangeName exchangeName(exchangeNameEnum, account);
const auto it = std::find(exchangeNames.begin() + posPublicExchangeName, exchangeNames.end(), exchangeName);
if (it == exchangeNames.end()) {
exchangeNames.push_back(std::move(exchangeName));
} else if (it >= exchangeNames.begin() + posMarket) {
throw invalid_argument("Duplicated account {} for exchange {}", account, exchangeName.name());
}
}
}
}
return exchangeNames;
}

ExchangeNameEnumVector AutoTradeOptions::publicExchanges() const {
ExchangeNameEnumVector exchanges;
for (const auto &[publicExchangeName, _] : _autoTradeConfig) {
exchanges.emplace_back(publicExchangeName);
}
std::ranges::sort(exchanges);
return exchanges;
}

AutoTradeOptions::AccountAutoTradeOptionsPtrVector AutoTradeOptions::accountAutoTradeOptionsPtr(
std::string_view publicExchangeName) const {
AccountAutoTradeOptionsPtrVector accountAutoTradeOptionsPtr;
for (const auto &[exchangeNameEnum, publicExchangeAutoTradeOptions] : _autoTradeConfig) {
if (kSupportedExchanges[static_cast<int>(exchangeNameEnum)] == publicExchangeName) {
accountAutoTradeOptionsPtr.emplace_back(&publicExchangeAutoTradeOptions);
}
}
return accountAutoTradeOptionsPtr;
}

const schema::AutoTradeExchangeConfig &AutoTradeOptions::operator[](ExchangeNameEnum exchangeNameEnum) const {
const auto it = std::ranges::find_if(_autoTradeConfig, [exchangeNameEnum](const auto &exchangeConfig) {
return exchangeConfig.first == exchangeNameEnum;
});
if (it == _autoTradeConfig.end()) {
throw exception("No auto trade options for exchange {}", kSupportedExchanges[static_cast<int>(exchangeNameEnum)]);
}
return it->second;
}

} // namespace cct
Loading

0 comments on commit 32634ca

Please sign in to comment.