remove fee table path: fee rate now computed solely from formula fee_category * 0.001 * taker_fee_coeff

This commit is contained in:
nicolas 2026-05-29 09:49:37 -03:00
parent faa88070e7
commit 405fc557dc
5 changed files with 17 additions and 131 deletions

View File

@ -70,32 +70,6 @@ int main(int argc, char *argv[]) {
log_write("[MAIN] Config: threshold=%.1f bps, cooldown=%.0fs, hold=%u currencies\n",
cfg.signal_threshold_bps, cfg.cooldown_seconds, cfg.hold_currency_count);
// Fetch fee table with auth (KuCoin /api/v1/base-fee)
fee_entry_t *fees = NULL;
uint32_t fee_count = 0;
log_write("[MAIN] API key present: %s\n", cfg.kucoin_api_key[0] ? "yes" : "no");
if (cfg.kucoin_api_key[0] && cfg.kucoin_api_secret[0] && cfg.kucoin_api_passphrase[0]) {
log_write("[MAIN] >>> Calling https_get_auth for /api/v1/base-fee\n");
int out_len = 0;
char *fee_json = https_get_auth("api.kucoin.com", 443, "/api/v1/base-fee",
cfg.kucoin_api_key, cfg.kucoin_api_secret,
cfg.kucoin_api_passphrase, &out_len);
log_write("[MAIN] <<< https_get_auth returned: %p, len=%d\n", fee_json, out_len);
if (fee_json && out_len > 0) {
if (load_fee_table(fee_json, &fees, &fee_count) == 0) {
log_write("[MAIN] Fee table: %u currencies loaded\n", fee_count);
} else {
log_write("[MAIN] Fee table parse failed, using default 0.1%% fees\n");
}
free(fee_json);
} else {
log_write("[MAIN] Could not fetch fee table, using default 0.1%% fees\n");
}
} else {
log_write("[MAIN] No API credentials in config, using default 0.1%% fees\n");
}
// Discover symbols from KuCoin: fetch pairs, enumerate triangles, populate table
log_write("[MAIN] >>> Initializing symbol table\n");
symbol_table_t symbols;
@ -107,9 +81,8 @@ int main(int argc, char *argv[]) {
log_write("[MAIN] >>> Calling discover_symbols\n");
triangle_set_t triangles;
if (discover_symbols(&symbols, &triangles, &cfg, fees, fee_count) != 0) {
if (discover_symbols(&symbols, &triangles, &cfg) != 0) {
log_write("[MAIN] Symbol discovery failed\n");
free_fee_table(fees);
return 1;
}
log_write("[MAIN] <<< discover_symbols done: %u symbols, %u triangles\n", symbols.count, triangles.triangle_count);
@ -120,7 +93,7 @@ int main(int argc, char *argv[]) {
if (!books) {
log_write("[MAIN] Failed to allocate books\n");
free_fee_table(fees);
return 1;
}
@ -130,7 +103,7 @@ int main(int argc, char *argv[]) {
executor_slot_t *slots = calloc((size_t)n_slots, sizeof(executor_slot_t));
if (!slots) {
log_write("[MAIN] Failed to allocate slots\n");
free_fee_table(fees);
return 1;
}
for (int i = 0; i < n_slots; i++) {
@ -139,7 +112,7 @@ int main(int argc, char *argv[]) {
log_write("[MAIN] Failed to create slot eventfd\n");
for (int j = 0; j < i; j++) close(slots[j].eventfd);
free(slots);
free_fee_table(fees);
return 1;
}
}
@ -153,7 +126,7 @@ int main(int argc, char *argv[]) {
if (ws_client_init(&ws_client, &cfg, &symbols, books, &evaluator) != 0) {
log_write("[MAIN] Failed to init WS client\n");
triangle_set_free(&triangles);
free_fee_table(fees);
return 1;
}
@ -162,7 +135,7 @@ int main(int argc, char *argv[]) {
log_write("[MAIN] Failed to init event loops\n");
ws_client_destroy(&ws_client);
triangle_set_free(&triangles);
free_fee_table(fees);
return 1;
}
@ -273,7 +246,6 @@ int main(int argc, char *argv[]) {
free(slots);
triangle_set_free(&triangles);
free(books);
free_fee_table(fees);
log_write("[MAIN] Shutdown complete.\n");
log_shutdown();

View File

@ -91,17 +91,7 @@ static bool ph_find(const pair_hash_t *ph, const char *c1, const char *c2, uint3
/* Fee rate per category: cat1=0.1%, cat2=0.2%, cat3=0.3%.
Looks up the fee_currency in the fee table first; falls back to category formula. */
static double fee_rate_for_pair(const trading_pair_t *pair, bool kcs_discount,
const fee_entry_t *fees, uint32_t fee_count) {
if (fees && fee_count > 0) {
for (uint32_t i = 0; i < fee_count; i++) {
if (strcmp(fees[i].currency, "ALL") == 0 ||
strcmp(fees[i].currency, pair->fee_currency) == 0) {
double rate = fees[i].taker_fee;
return kcs_discount ? rate * 0.8 : rate;
}
}
}
static double fee_rate_for_pair(const trading_pair_t *pair, bool kcs_discount) {
double base = pair->fee_category * 0.001;
double rate = base * pair->taker_fee_coeff;
return kcs_discount ? rate * 0.8 : rate;
@ -223,7 +213,7 @@ int fetch_trading_pairs(pair_list_t *out) {
* tri_index (symbol -> flat triangle list) for fast symbol-based lookup.
*/
int discover_symbols(symbol_table_t *symbols, triangle_set_t *triangles,
const config_t *cfg, const fee_entry_t *fees, uint32_t fee_count) {
const config_t *cfg) {
pair_list_t pairs;
if (fetch_trading_pairs(&pairs) != 0) {
log_write("[SYMBOLS] Failed to fetch pairs\n");
@ -358,9 +348,9 @@ int discover_symbols(symbol_table_t *symbols, triangle_set_t *triangles,
{ size_t _l = strlen(hold); if (_l >= CURRENCY_NAME_LEN) _l = CURRENCY_NAME_LEN - 1; memcpy(t->base, hold, _l); t->base[_l] = '\0'; }
{ size_t _l = strlen(x); if (_l >= CURRENCY_NAME_LEN) _l = CURRENCY_NAME_LEN - 1; memcpy(t->mid, x, _l); t->mid[_l] = '\0'; }
{ size_t _l = strlen(y); if (_l >= CURRENCY_NAME_LEN) _l = CURRENCY_NAME_LEN - 1; memcpy(t->quote, y, _l); t->quote[_l] = '\0'; }
t->fee_factor[0] = 1.0 - fee_rate_for_pair(&pairs.pairs[i1], kcs, fees, fee_count);
t->fee_factor[1] = 1.0 - fee_rate_for_pair(&pairs.pairs[i2], kcs, fees, fee_count);
t->fee_factor[2] = 1.0 - fee_rate_for_pair(&pairs.pairs[i3], kcs, fees, fee_count);
t->fee_factor[0] = 1.0 - fee_rate_for_pair(&pairs.pairs[i1], kcs);
t->fee_factor[1] = 1.0 - fee_rate_for_pair(&pairs.pairs[i2], kcs);
t->fee_factor[2] = 1.0 - fee_rate_for_pair(&pairs.pairs[i3], kcs);
t->base_increment[0] = pairs.pairs[i1].base_increment;
t->base_increment[1] = pairs.pairs[i2].base_increment;
t->base_increment[2] = pairs.pairs[i3].base_increment;

View File

@ -35,6 +35,6 @@ int fetch_trading_pairs(pair_list_t *out);
/* Full symbol discovery: fetch pairs, enumerate triangles, populate tables */
int discover_symbols(symbol_table_t *symbols, triangle_set_t *triangles,
const config_t *cfg, const fee_entry_t *fees, uint32_t fee_count);
const config_t *cfg);
#endif

View File

@ -1,22 +1,17 @@
/*
* triangle.c - Triangle data structure management and fee table parsing
* triangle.c - Triangle data structure management
*
* triangle_set_init is a stub; actual triangle enumeration happens in
* symbols_api.c:discover_symbols. This file provides fee parsing from
* KuCoin's /api/v1/base-fee response (both object and array formats).
* symbols_api.c:discover_symbols.
*/
#include "triangle.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "cJSON.h"
int triangle_set_init(triangle_set_t *set, const symbol_table_t *symbols,
const config_t *cfg, const fee_entry_t *fees,
uint32_t fee_count) {
/* Triangle enumeration is now done in discover_symbols (symbols_api.c) */
(void)set; (void)symbols; (void)cfg; (void)fees; (void)fee_count;
const config_t *cfg) {
(void)set; (void)symbols; (void)cfg;
return 0;
}
@ -29,68 +24,3 @@ void triangle_set_free(triangle_set_t *set) {
set->tri_flat = NULL;
set->triangle_count = 0;
}
/*
* Parse KuCoin /api/v1/base-fee JSON response.
* Supports two formats:
* - Object: {"takerFeeRate": 0.001, ...}
* - Array: [{"currency": "BTC", "takerFeeRate": 0.001}, ...]
* Stores result as fee_entry_t array (single "ALL" entry for object format).
*/
int load_fee_table(const char *json, fee_entry_t **out_fees, uint32_t *out_count) {
cJSON *root = cJSON_Parse(json);
if (!root) return -1;
cJSON *code = cJSON_GetObjectItem(root, "code");
if (!cJSON_IsString(code) || strcmp(code->valuestring, "200000") != 0) {
cJSON_Delete(root);
return -1;
}
cJSON *data = cJSON_GetObjectItem(root, "data");
if (!data) {
cJSON_Delete(root);
return -1;
}
*out_count = 0;
if (cJSON_IsObject(data)) {
// Single global fee rate
*out_fees = calloc(1, sizeof(fee_entry_t));
if (!*out_fees) { cJSON_Delete(root); return -1; }
fee_entry_t *fee = *out_fees;
strncpy(fee->currency, "ALL", CURRENCY_NAME_LEN - 1);
cJSON *taker = cJSON_GetObjectItem(data, "takerFeeRate");
cJSON *maker = cJSON_GetObjectItem(data, "makerFeeRate");
if (cJSON_IsNumber(taker)) fee->taker_fee = taker->valuedouble;
if (cJSON_IsNumber(maker)) fee->maker_fee = maker->valuedouble;
*out_count = 1;
} else if (cJSON_IsArray(data)) {
// Per-currency fee rates array
int arr_size = cJSON_GetArraySize(data);
*out_fees = calloc(arr_size, sizeof(fee_entry_t));
if (!*out_fees) { cJSON_Delete(root); return -1; }
cJSON *item;
int idx = 0;
cJSON_ArrayForEach(item, data) {
if (!cJSON_IsObject(item)) continue;
fee_entry_t *fee = &((*out_fees)[idx]);
cJSON *cur = cJSON_GetObjectItem(item, "currency");
cJSON *taker = cJSON_GetObjectItem(item, "takerFeeRate");
cJSON *maker = cJSON_GetObjectItem(item, "makerFeeRate");
if (cJSON_IsString(cur)) strncpy(fee->currency, cur->valuestring, CURRENCY_NAME_LEN - 1);
if (cJSON_IsNumber(taker)) fee->taker_fee = taker->valuedouble;
if (cJSON_IsNumber(maker)) fee->maker_fee = maker->valuedouble;
idx++;
}
*out_count = idx;
}
cJSON_Delete(root);
return 0;
}
void free_fee_table(fee_entry_t *fees) {
free(fees);
}

View File

@ -111,14 +111,8 @@ typedef struct {
/* Initialise triangle set: enumerate all triangles from the symbol table */
int triangle_set_init(triangle_set_t *set, const symbol_table_t *symbols,
const config_t *cfg, const fee_entry_t *fees,
uint32_t fee_count);
const config_t *cfg);
/* Free all memory owned by a triangle set */
void triangle_set_free(triangle_set_t *set);
/* Parse fee table JSON into an array of fee_entry_t */
int load_fee_table(const char *json, fee_entry_t **out_fees, uint32_t *out_count);
/* Free a fee table array */
void free_fee_table(fee_entry_t *fees);
#endif