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

[WIP] Auto-trade mode #600

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
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
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
Loading