Skip to content

Commit bd91d7a

Browse files
committed
Live auto trade mode
1 parent e18cb15 commit bd91d7a

18 files changed

+576
-8
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,51 @@
1+
#pragma once
2+
3+
#include <compare>
4+
#include <functional>
5+
6+
#include "auto-trade-config.hpp"
7+
#include "cct_smallvector.hpp"
8+
#include "cct_vector.hpp"
9+
#include "exchange-names.hpp"
10+
#include "exchange.hpp"
11+
#include "market.hpp"
12+
#include "timedef.hpp"
13+
14+
namespace cct {
15+
class AutoTradeOptions;
16+
17+
class AutoTradeProcessor {
18+
public:
19+
explicit AutoTradeProcessor(const AutoTradeOptions& autoTradeOptions);
20+
21+
struct SelectedMarket {
22+
ExchangeNames privateExchangeNames;
23+
Market market;
24+
};
25+
26+
using SelectedMarketVector = SmallVector<SelectedMarket, kTypicalNbPrivateAccounts>;
27+
28+
SelectedMarketVector computeSelectedMarkets();
29+
30+
private:
31+
struct MarketStatus {
32+
ExchangeNames privateExchangeNames;
33+
Market market;
34+
TimePoint lastQueryTime;
35+
const schema::AutoTradeMarketConfig* pMarketAutoTradeOptions{};
36+
};
37+
38+
using MarketStatusVector = vector<MarketStatus>;
39+
40+
struct ExchangeStatus {
41+
MarketStatusVector marketStatusVector;
42+
const schema::AutoTradeExchangeConfig* pPublicExchangeAutoTradeOptions{};
43+
};
44+
45+
using ExchangeStatusVector = SmallVector<ExchangeStatus, kTypicalNbPrivateAccounts>;
46+
47+
ExchangeStatusVector _exchangeStatusVector;
48+
TimePoint _startTs = Clock::now();
49+
TimePoint _ts{_startTs};
50+
};
51+
} // namespace cct

src/engine/include/coincenter.hpp

+4
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

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

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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 = _autoTradeConfig.find(exchangeNameEnum);
55+
if (it == _autoTradeConfig.end()) {
56+
throw exception("No auto trade options for exchange {}", kSupportedExchanges[static_cast<int>(exchangeNameEnum)]);
57+
}
58+
return it->second;
59+
}
60+
61+
} // namespace cct

0 commit comments

Comments
 (0)