Skip to content

Commit 7df208e

Browse files
committedJan 18, 2025
Live auto trade mode
1 parent 6c6adcc commit 7df208e

20 files changed

+634
-15
lines changed
 

‎data/static/auto-trade-example.json

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"kraken": {
3+
"BTC-EUR": {
4+
"accounts": [
5+
"user1",
6+
"user2"
7+
],
8+
"algorithmName": "example-trader",
9+
"repeatTime": "5s",
10+
"baseStartAmount": "0.5BTC",
11+
"quoteStartAmount": "50%EUR",
12+
"stopCriteria": [
13+
{
14+
"type": "duration",
15+
"value": "4h"
16+
},
17+
{
18+
"type": "protectLoss",
19+
"value": "-30%"
20+
},
21+
{
22+
"type": "secureProfit",
23+
"value": "80%"
24+
}
25+
]
26+
},
27+
"ETH-EUR": {
28+
"accounts": [
29+
"user1"
30+
],
31+
"algorithmName": "example-trader",
32+
"repeatTime": "3s",
33+
"baseStartAmount": "45ETH",
34+
"quoteStartAmount": "50%EUR",
35+
"stopCriteria": [
36+
{
37+
"type": "duration",
38+
"value": "4h"
39+
},
40+
{
41+
"type": "protectLoss",
42+
"value": "-30%"
43+
},
44+
{
45+
"type": "secureProfit",
46+
"value": "80%"
47+
}
48+
]
49+
}
50+
},
51+
"binance": {
52+
"XRP-USDT": {
53+
"accounts": [
54+
"user1"
55+
],
56+
"algorithmName": "example-trader",
57+
"repeatTime": "1s",
58+
"baseStartAmount": "50000.56XRP",
59+
"quoteStartAmount": "100%USDT",
60+
"stopCriteria": []
61+
}
62+
}
63+
}

‎src/basic-objects/include/coincentercommandtype.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace cct {
1313
Balance, DepositInfo, OrdersClosed, OrdersOpened, OrdersCancel, RecentDeposits, RecentWithdraws, Trade, Buy, \
1414
Sell, Withdraw, DustSweeper, \
1515
\
16-
MarketData, Replay, ReplayMarkets
16+
MarketData, Replay, ReplayMarkets, AutoTrade
1717

1818
enum class CoincenterCommandType : int8_t { CCT_COINCENTER_COMMAND_TYPES };
1919

@@ -26,4 +26,4 @@ struct glz::meta<::cct::CoincenterCommandType> {
2626
static constexpr auto value = enumerate(CCT_COINCENTER_COMMAND_TYPES);
2727
};
2828

29-
#undef CCT_COINCENTER_COMMAND_TYPES
29+
#undef CCT_COINCENTER_COMMAND_TYPES
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#pragma once
2+
3+
#include <map>
4+
5+
#include "auto-trade-config.hpp"
6+
#include "cct_const.hpp"
7+
#include "cct_fixedcapacityvector.hpp"
8+
#include "cct_smallvector.hpp"
9+
#include "cct_vector.hpp"
10+
#include "exchange-names.hpp"
11+
#include "exchangename.hpp"
12+
13+
namespace cct {
14+
15+
class AutoTradeOptions {
16+
public:
17+
using AccountAutoTradeOptionsPtrVector =
18+
SmallVector<const schema::AutoTradeExchangeConfig *, kTypicalNbPrivateAccounts>;
19+
20+
struct MarketExchanges {
21+
Market market;
22+
ExchangeNames privateExchangeNames;
23+
const schema::AutoTradeMarketConfig *pMarketAutoTradeOptions{};
24+
};
25+
26+
using MarketStatusVector = vector<MarketExchanges>;
27+
28+
struct MarketExchangeOptions {
29+
MarketStatusVector marketStatusVector;
30+
};
31+
32+
struct PublicExchangeMarketOptions {
33+
ExchangeName publicExchangeName;
34+
MarketExchangeOptions marketExchangeOptions;
35+
};
36+
37+
using PublicExchangeMarketOptionsVector = FixedCapacityVector<schema::AutoTradeExchangeConfig, kNbSupportedExchanges>;
38+
39+
AutoTradeOptions() noexcept = default;
40+
41+
explicit AutoTradeOptions(schema::AutoTradeConfig &&autoTradeConfig);
42+
43+
auto begin() const { return _autoTradeConfig.begin(); }
44+
auto end() const { return _autoTradeConfig.end(); }
45+
46+
ExchangeNames exchangeNames() const;
47+
48+
ExchangeNameEnumVector publicExchanges() const;
49+
50+
AccountAutoTradeOptionsPtrVector accountAutoTradeOptionsPtr(std::string_view publicExchangeName) const;
51+
52+
const schema::AutoTradeExchangeConfig &operator[](ExchangeNameEnum exchangeNameEnum) const;
53+
54+
private:
55+
schema::AutoTradeConfig _autoTradeConfig;
56+
};
57+
58+
} // namespace cct
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#pragma once
2+
3+
#include <array>
4+
#include <compare>
5+
#include <functional>
6+
#include <unordered_map>
7+
8+
#include "auto-trade-config.hpp"
9+
#include "cct_smallvector.hpp"
10+
#include "cct_vector.hpp"
11+
#include "exchange-names.hpp"
12+
#include "exchange.hpp"
13+
#include "market-trader-engine.hpp"
14+
#include "market.hpp"
15+
#include "timedef.hpp"
16+
17+
namespace cct {
18+
class AutoTradeOptions;
19+
class CoincenterInfo;
20+
21+
class AutoTradeProcessor {
22+
public:
23+
using MarketTraderEngines = std::array<std::unordered_map<Market, MarketTraderEngine>, kNbSupportedExchanges>;
24+
25+
explicit AutoTradeProcessor(const AutoTradeOptions& autoTradeOptions);
26+
27+
struct SelectedMarket {
28+
ExchangeNames privateExchangeNames;
29+
Market market;
30+
};
31+
32+
using SelectedMarketVector = SmallVector<SelectedMarket, kTypicalNbPrivateAccounts>;
33+
34+
SelectedMarketVector computeSelectedMarkets();
35+
36+
MarketTraderEngines createMarketTraderEngines(const CoincenterInfo& coincenterInfo) const;
37+
38+
private:
39+
struct MarketStatus {
40+
ExchangeNames privateExchangeNames;
41+
Market market;
42+
TimePoint lastQueryTime;
43+
const schema::AutoTradeMarketConfig* pMarketAutoTradeOptions{};
44+
};
45+
46+
using MarketStatusVector = vector<MarketStatus>;
47+
48+
struct ExchangeStatus {
49+
MarketStatusVector marketStatusVector;
50+
const schema::AutoTradeExchangeConfig* pPublicExchangeAutoTradeOptions{};
51+
ExchangeNameEnum exchangeNameEnum;
52+
};
53+
54+
using ExchangeStatusVector = SmallVector<ExchangeStatus, kTypicalNbPrivateAccounts>;
55+
56+
ExchangeStatusVector _exchangeStatusVector;
57+
TimePoint _startTs = Clock::now();
58+
TimePoint _ts{_startTs};
59+
};
60+
} // namespace cct

‎src/engine/include/coincenter.hpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <span>
55

66
#include "apikeysprovider.hpp"
7+
#include "auto-trade-options.hpp"
78
#include "cct_const.hpp"
89
#include "cct_fixedcapacityvector.hpp"
910
#include "coincenterinfo.hpp"
@@ -149,6 +150,9 @@ class Coincenter {
149150
ReplayResults replay(const AbstractMarketTraderFactory &marketTraderFactory, const ReplayOptions &replayOptions,
150151
Market market, ExchangeNameSpan exchangeNames);
151152

153+
/// Run auto trade.
154+
void autoTrade(const AutoTradeOptions &autoTradeOptions);
155+
152156
/// Dumps the content of all file caches in data directory to save cURL queries.
153157
void updateFileCaches() const;
154158

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

175179
// TODO: may be moved somewhere else?
176-
MarketTraderEngineVector createMarketTraderEngines(const ReplayOptions &replayOptions, Market market,
177-
ExchangeNameEnumVector &exchangesWithThisMarketData);
180+
MarketTraderEngineVector createMarketTraderEnginesForReplay(const ReplayOptions &replayOptions, Market market,
181+
ExchangeNameEnumVector &exchangesWithThisMarketData);
178182

179183
MarketTradeRangeStatsPerExchange tradingProcess(const ReplayOptions &replayOptions,
180184
std::span<MarketTraderEngine> marketTraderEngines,

‎src/engine/include/coincentercommand.hpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <cstdint>
44
#include <optional>
5+
#include <string_view>
56
#include <type_traits>
67
#include <variant>
78

@@ -47,6 +48,8 @@ class CoincenterCommand {
4748

4849
CoincenterCommand& setReplayOptions(ReplayOptions replayOptions);
4950

51+
CoincenterCommand& setJsonConfigFile(std::string_view jsonConfigFile);
52+
5053
CoincenterCommand& setPercentageAmount(bool value = true);
5154
CoincenterCommand& withBalanceInUse(bool value = true);
5255

@@ -79,6 +82,8 @@ class CoincenterCommand {
7982

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

85+
std::string_view getJsonConfigFile() const { return std::get<std::string_view>(_specialOptions); }
86+
8287
bool operator==(const CoincenterCommand&) const noexcept = default;
8388

8489
using trivially_relocatable =
@@ -89,7 +94,7 @@ class CoincenterCommand {
8994

9095
private:
9196
using SpecialOptions = std::variant<std::monostate, OrdersConstraints, WithdrawsOrDepositsConstraints, TradeOptions,
92-
WithdrawOptions, ReplayOptions>;
97+
WithdrawOptions, ReplayOptions, std::string_view>;
9398

9499
ExchangeNames _exchangeNames;
95100
SpecialOptions _specialOptions;

‎src/engine/include/coincenteroptions.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ class CoincenterCmdLineOptions {
104104

105105
std::string_view marketData;
106106

107+
std::string_view autoTrade;
108+
107109
std::optional<std::string_view> replay;
108110
std::string_view algorithmNames;
109111
std::string_view market;

‎src/engine/include/coincenteroptionsdef.hpp

+16
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,22 @@ struct CoincenterAllowedOptions : private CoincenterCmdLineOptionsDefinitions {
477477
"\nNominal replay will not validate input data to optimize performance, use this option to validate data once "
478478
"and for all."},
479479
&OptValueType::validateOnly},
480+
{{{"Automation", 8004},
481+
"auto-trade",
482+
"<path/to/json.conf>",
483+
"Automatic live trading mode. Once you have validated on historical market-data the performance of an "
484+
"algorithm, it's time to try it for real!\n"
485+
"This command has some particularities:\n"
486+
"- next commands will never be executed\n"
487+
"- repeat is ignored (the auto trade will continue until one of terminating signals defined in the "
488+
"configuration file is reached)\n"
489+
"Configuration will be loaded from given json file, with following options (check README to get full "
490+
"configuration schema):\n"
491+
"- 'algorithm' : algorithm name to use\n"
492+
"- 'market' : the market to trade onto\n"
493+
"- 'startAmount' : the starting amount in base currency (can be a percentage of available amount)\n"
494+
"- 'exchange' : exchange with account key (not needed if not ambiguous)"},
495+
&OptValueType::autoTrade},
480496
{{{"Monitoring", 9000},
481497
"--monitoring",
482498
"",

‎src/engine/include/exchangesorchestrator.hpp

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#include <optional>
44
#include <span>
55

6+
#include "auto-trade-options.hpp"
7+
#include "auto-trade-processor.hpp"
68
#include "exchange-names.hpp"
79
#include "exchangename.hpp"
810
#include "exchangeretriever.hpp"

‎src/engine/src/auto-trade-options.cpp

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "auto-trade-options.hpp"
2+
3+
#include <utility>
4+
5+
#include "auto-trade-config.hpp"
6+
#include "cct_invalid_argument_exception.hpp"
7+
8+
namespace cct {
9+
10+
AutoTradeOptions::AutoTradeOptions(schema::AutoTradeConfig &&autoTradeConfig)
11+
: _autoTradeConfig(std::move(autoTradeConfig)) {}
12+
13+
ExchangeNames AutoTradeOptions::exchangeNames() const {
14+
ExchangeNames exchangeNames;
15+
for (const auto &[exchangeNameEnum, publicExchangeAutoTradeOptions] : _autoTradeConfig) {
16+
const int posPublicExchangeName = exchangeNames.size();
17+
for (const auto &[market, autoTradeMarketConfig] : publicExchangeAutoTradeOptions) {
18+
const int posMarket = exchangeNames.size();
19+
for (std::string_view account : autoTradeMarketConfig.accounts) {
20+
ExchangeName exchangeName(exchangeNameEnum, account);
21+
const auto it = std::find(exchangeNames.begin() + posPublicExchangeName, exchangeNames.end(), exchangeName);
22+
if (it == exchangeNames.end()) {
23+
exchangeNames.push_back(std::move(exchangeName));
24+
} else if (it >= exchangeNames.begin() + posMarket) {
25+
throw invalid_argument("Duplicated account {} for exchange {}", account, exchangeName.name());
26+
}
27+
}
28+
}
29+
}
30+
return exchangeNames;
31+
}
32+
33+
ExchangeNameEnumVector AutoTradeOptions::publicExchanges() const {
34+
ExchangeNameEnumVector exchanges;
35+
for (const auto &[publicExchangeName, _] : _autoTradeConfig) {
36+
exchanges.emplace_back(publicExchangeName);
37+
}
38+
std::ranges::sort(exchanges);
39+
return exchanges;
40+
}
41+
42+
AutoTradeOptions::AccountAutoTradeOptionsPtrVector AutoTradeOptions::accountAutoTradeOptionsPtr(
43+
std::string_view publicExchangeName) const {
44+
AccountAutoTradeOptionsPtrVector accountAutoTradeOptionsPtr;
45+
for (const auto &[exchangeNameEnum, publicExchangeAutoTradeOptions] : _autoTradeConfig) {
46+
if (kSupportedExchanges[static_cast<int>(exchangeNameEnum)] == publicExchangeName) {
47+
accountAutoTradeOptionsPtr.emplace_back(&publicExchangeAutoTradeOptions);
48+
}
49+
}
50+
return accountAutoTradeOptionsPtr;
51+
}
52+
53+
const schema::AutoTradeExchangeConfig &AutoTradeOptions::operator[](ExchangeNameEnum exchangeNameEnum) const {
54+
const auto it = std::ranges::find_if(_autoTradeConfig, [exchangeNameEnum](const auto &exchangeConfig) {
55+
return exchangeConfig.first == exchangeNameEnum;
56+
});
57+
if (it == _autoTradeConfig.end()) {
58+
throw exception("No auto trade options for exchange {}", kSupportedExchanges[static_cast<int>(exchangeNameEnum)]);
59+
}
60+
return it->second;
61+
}
62+
63+
} // namespace cct

0 commit comments

Comments
 (0)
Please sign in to comment.