feat: add allow_same_quote config, fix overlapping pair isolation to check all 3 legs, document config example
This commit is contained in:
parent
60257f068f
commit
930365f072
|
|
@ -1,23 +1,54 @@
|
|||
# Live trading mode. false = paper trades (test endpoint, no real orders).
|
||||
live_mode: false
|
||||
|
||||
fused_engine:
|
||||
# Log verbosity: INFO, DEBUG, or WARN
|
||||
log_level: INFO
|
||||
|
||||
# Minimum predicted profit in basis points (0.01%) to fire a signal
|
||||
signal_threshold_bps: 2
|
||||
|
||||
# Currencies to exclude from triangle enumeration entirely
|
||||
excluded_currencies: [EUR, BRL]
|
||||
|
||||
# Currencies the bot holds as capital. Triangles must start and end in one of these.
|
||||
hold_currencies: [USDT, USDC, USD1]
|
||||
|
||||
# KuCoin WebSocket base URL (override for alternate endpoint)
|
||||
ws_url: wss://ws-api-spot.kucoin.com
|
||||
|
||||
# KuCoin token endpoint (public bullet for WS credentials)
|
||||
token_url: https://api.kucoin.com/api/v1/bullet-public
|
||||
|
||||
# Initial WebSocket reconnect delay in seconds (exponential backoff)
|
||||
reconnect_base_delay: 1.0
|
||||
|
||||
# Maximum WebSocket reconnect delay in seconds
|
||||
reconnect_max_delay: 60.0
|
||||
|
||||
# WebSocket ping interval in seconds
|
||||
heartbeat_interval: 18.0
|
||||
|
||||
# If true, apply 20% discount to fee rates (KCS holding benefit)
|
||||
kcs_discount_active: false
|
||||
|
||||
# Number of parallel executor threads (each owns one signal slot, max 16)
|
||||
concurrent_slots: 1
|
||||
|
||||
# Wait for WS balance settlement between live legs (requires private WS channel)
|
||||
balance_wait_enabled: false
|
||||
|
||||
# Allow parallel triangles that share the same primary quote currency
|
||||
# Useful when exchange balance can support multiple concurrent trades
|
||||
allow_same_quote: false
|
||||
|
||||
# Maximum quote amount per triangle signal, per currency
|
||||
initial_capital:
|
||||
USDT: 5
|
||||
USDC: 5
|
||||
USD1: 5
|
||||
|
||||
# KuCoin API credentials for authenticated endpoints (top-level keys)
|
||||
kucoin_api_key: ""
|
||||
kucoin_api_secret: ""
|
||||
kucoin_api_passphrase: ""
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ static void handle_value(parse_state_t *st, const char *val) {
|
|||
st->cfg->concurrent_slots = atoi(val);
|
||||
} else if (strcmp(key, "balance_wait_enabled") == 0) {
|
||||
st->cfg->balance_wait_enabled = (strcmp(val, "true") == 0 || strcmp(val, "yes") == 0);
|
||||
} else if (strcmp(key, "allow_same_quote") == 0) {
|
||||
st->cfg->allow_same_quote = (strcmp(val, "true") == 0 || strcmp(val, "yes") == 0);
|
||||
}
|
||||
} else if (strcmp(st->section, "executor") == 0) {
|
||||
return;
|
||||
|
|
@ -124,6 +126,7 @@ int config_load(const char *path, config_t *cfg) {
|
|||
cfg->concurrent_slots = 1;
|
||||
cfg->live_mode = false;
|
||||
cfg->balance_wait_enabled = false;
|
||||
cfg->allow_same_quote = false;
|
||||
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ typedef struct {
|
|||
int concurrent_slots; /* number of executor threads (1 = single-threaded) */
|
||||
bool live_mode; /* live trading vs paper/simulation */
|
||||
bool balance_wait_enabled; /* wait for WS balance settlement between legs */
|
||||
bool allow_same_quote; /* allow same primary quote in parallel triangles */
|
||||
|
||||
/* Capital allocation limits — each entry maps a currency ticker to a max
|
||||
* quote amount the fused engine may deploy for any one triangle signal. */
|
||||
|
|
|
|||
|
|
@ -146,16 +146,18 @@ void executor_execute_triangle(executor_thread_t *et,
|
|||
log_write("[EXEC] Dropping signal for overlapping triangle: %s\n", sig->triangle_key);
|
||||
return;
|
||||
}
|
||||
if (strcmp(sh->primary_quotes[i], sig->primary_quote) == 0) {
|
||||
if (!et->cfg->allow_same_quote && strcmp(sh->primary_quotes[i], sig->primary_quote) == 0) {
|
||||
pthread_mutex_unlock(&sh->lock);
|
||||
log_write("[EXEC] Dropping signal for same primary quote: %s\n", sig->triangle_key);
|
||||
return;
|
||||
}
|
||||
for (int p = 0; p < 3; p++) {
|
||||
if (sh->pairs[i] == pair_hashes[p]) {
|
||||
pthread_mutex_unlock(&sh->lock);
|
||||
log_write("[EXEC] Dropping signal for overlapping pair on %s\n", sig->triangle_key);
|
||||
return;
|
||||
for (int k = 0; k < 3; k++) {
|
||||
if (sh->pairs[i][k] == pair_hashes[p]) {
|
||||
pthread_mutex_unlock(&sh->lock);
|
||||
log_write("[EXEC] Dropping signal for overlapping pair on %s\n", sig->triangle_key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -167,7 +169,9 @@ void executor_execute_triangle(executor_thread_t *et,
|
|||
if (slot >= 0) {
|
||||
strncpy(sh->triangles[slot], sig->triangle_key, sizeof(sh->triangles[slot]) - 1);
|
||||
strncpy(sh->primary_quotes[slot], sig->primary_quote, sizeof(sh->primary_quotes[slot]) - 1);
|
||||
sh->pairs[slot] = pair_hashes[0];
|
||||
sh->pairs[slot][0] = pair_hashes[0];
|
||||
sh->pairs[slot][1] = pair_hashes[1];
|
||||
sh->pairs[slot][2] = pair_hashes[2];
|
||||
sh->count++;
|
||||
}
|
||||
pthread_mutex_unlock(&sh->lock);
|
||||
|
|
@ -493,7 +497,9 @@ void executor_execute_triangle(executor_thread_t *et,
|
|||
if (strcmp(sh->triangles[i], sig->triangle_key) == 0) {
|
||||
sh->triangles[i][0] = '\0';
|
||||
sh->primary_quotes[i][0] = '\0';
|
||||
sh->pairs[i] = 0;
|
||||
sh->pairs[i][0] = 0;
|
||||
sh->pairs[i][1] = 0;
|
||||
sh->pairs[i][2] = 0;
|
||||
if (sh->count > 0) sh->count--;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
typedef struct {
|
||||
pthread_mutex_t lock;
|
||||
char triangles[MAX_IN_FLIGHT][128];
|
||||
uint64_t pairs[MAX_IN_FLIGHT];
|
||||
uint64_t pairs[MAX_IN_FLIGHT][3];
|
||||
char primary_quotes[MAX_IN_FLIGHT][16];
|
||||
int count;
|
||||
char last_triangles[MAX_TRACKED_TRIANGLES][128];
|
||||
|
|
|
|||
Loading…
Reference in New Issue