Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b931d83

Browse files
committedNov 19, 2024·
Live auto trade mode
1 parent 1d25e51 commit b931d83

22 files changed

+699
-9
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
@@ -14,7 +14,7 @@ namespace cct {
1414
Balance, DepositInfo, OrdersClosed, OrdersOpened, OrdersCancel, RecentDeposits, RecentWithdraws, Trade, Buy, \
1515
Sell, Withdraw, DustSweeper, \
1616
\
17-
MarketData, Replay, ReplayMarkets
17+
MarketData, Replay, ReplayMarkets, AutoTrade
1818

1919
enum class CoincenterCommandType : int8_t { CCT_COINCENTER_COMMAND_TYPES };
2020

@@ -29,4 +29,4 @@ struct glz::meta<::cct::CoincenterCommandType> {
2929
static constexpr auto value = enumerate(CCT_COINCENTER_COMMAND_TYPES);
3030
};
3131

32-
#undef CCT_COINCENTER_COMMAND_TYPES
32+
#undef CCT_COINCENTER_COMMAND_TYPES

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ struct from<JSON, ::cct::Market> {
163163
static void op(auto &&value, is_context auto &&, It &&it, End &&end) noexcept {
164164
// used as a value. As a key, the first quote will not be present.
165165
auto endIt = std::find(*it == '"' ? ++it : it, end, '"');
166-
value = std::string_view(it, endIt);
166+
value = ::cct::Market(std::string_view(it, endIt));
167167
it = ++endIt;
168168
}
169169
};

‎src/basic-objects/test/market_test.cpp

+43
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <gtest/gtest.h>
44

55
#include "cct_exception.hpp"
6+
#include "cct_json-serialization.hpp"
67
#include "currencycode.hpp"
78

89
namespace cct {
@@ -65,4 +66,46 @@ TEST(MarketTest, StrLen) {
6566
market = Market("1INCH", "EUR", Market::Type::kFiatConversionMarket);
6667
EXPECT_EQ(market.strLen(), 10);
6768
}
69+
70+
struct Foo {
71+
bool operator==(const Foo &) const noexcept = default;
72+
73+
Market market;
74+
};
75+
76+
TEST(MarketTest, JsonSerializationValue) {
77+
Foo foo{Market{"DOGE", "BTC"}};
78+
79+
string buffer;
80+
auto res = json::write<json::opts{.raw_string = true}>(foo, buffer); // NOLINT(readability-implicit-bool-conversion)
81+
82+
EXPECT_FALSE(res);
83+
84+
EXPECT_EQ(buffer, R"({"market":"DOGE-BTC"})");
85+
}
86+
87+
using MarketMap = std::map<Market, bool>;
88+
89+
TEST(MarketTest, JsonSerializationKey) {
90+
MarketMap map{{Market{"DOGE", "BTC"}, true}, {Market{"BTC", "ETH"}, false}};
91+
92+
string buffer;
93+
auto res = json::write<json::opts{.raw_string = true}>(map, buffer); // NOLINT(readability-implicit-bool-conversion)
94+
95+
EXPECT_FALSE(res);
96+
97+
EXPECT_EQ(buffer, R"({"BTC-ETH":false,"DOGE-BTC":true})");
98+
}
99+
100+
TEST(MarketTest, JsonDeserialization) {
101+
Foo foo;
102+
103+
// NOLINTNEXTLINE(readability-implicit-bool-conversion)
104+
auto ec = json::read<json::opts{.raw_string = true}>(foo, R"({"market":"DOGE-ETH"})");
105+
106+
ASSERT_FALSE(ec);
107+
108+
EXPECT_EQ(foo, Foo{Market("DOGE", "ETH")});
109+
}
110+
68111
} // namespace cct
+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"

0 commit comments

Comments
 (0)
Please sign in to comment.