9 size_t len = strlen(s) + 1;
10 char* copy = malloc(len);
11 if (copy) memcpy(copy, s, len);
23 .portfolio_value = portfolio_value,
24 .timestamp = timestamp
51 if (pnl < stats->max_loss)
61 const char* symbol,
double quantity,
double value,
double last_price) {
63 if (asset_index < 0)
return;
65 if (asset_index >= stats->
capacity) {
66 int new_capacity = asset_index + 1;
67 stats->
symbols = realloc(stats->
symbols, new_capacity *
sizeof(
char*));
69 stats->
values = realloc(stats->
values, new_capacity *
sizeof(
double));
71 for (
int i = stats->
capacity; i < new_capacity; i++) {
82 if (symbol && (!stats->
symbols[asset_index] ||
83 strcmp(stats->
symbols[asset_index], symbol) != 0)) {
84 free(stats->
symbols[asset_index]);
88 stats->
values[asset_index] = value;
93 if (!stats)
return NULL;
101 char* result = malloc(8192);
102 if (!result)
return NULL;
103 int offset = snprintf(result, 8192,
104 "initial_cash=%.2f current_cash=%.2f portfolio_value=%.2f "
105 "pnl=%.2f pnl_pct=%.2f tx_fees=%.2f borrow_interest=%.2f "
106 "total_trades=%ld winning_trades=%ld losing_trades=%ld "
107 "win_rate=%.2f max_win=%.2f max_loss=%.2f avg_pnl=%.2f pnl_stdev=%.2f "
108 "stop_loss_exits=%ld take_profit_exits=%ld",
113 isnan(pnl_stdev) ? 0.0 : pnl_stdev,
118 offset += snprintf(result + offset, 8192 - offset,
119 " max_drawdown=%.4f", mdd);
123 offset += snprintf(result + offset, 8192 - offset,
124 " sharpe_ratio=%.4f", isnan(sharpe) ? 0.0 : sharpe);
128 offset += snprintf(result + offset, 8192 - offset,
129 " sortino_ratio=%.4f", isnan(sortino) ? 0.0 : sortino);
133 offset += snprintf(result + offset, 8192 - offset,
134 " calmar_ratio=%.4f", isnan(calmar) ? 0.0 : calmar);
139 offset += snprintf(result + offset, 8192 - offset,
140 " %s_quantity=%.4f %s_value=%.2f %s_price=%.2f",
150 if (!stats)
return NULL;
151 const char* nl = pretty ?
"\n" :
"";
152 const char* indent1 = pretty ?
" " :
"";
153 const char* indent2 = pretty ?
" " :
"";
154 const char* space = pretty ?
" " :
"";
162 char* result = malloc(16384);
163 if (!result)
return NULL;
164 int offset = snprintf(result, 16384,
166 "%s\"portfolio\":%s{%s"
167 "%s\"initial_cash\":%s%.2f,%s"
168 "%s\"current_cash\":%s%.2f,%s"
169 "%s\"portfolio_value\":%s%.2f,%s"
170 "%s\"pnl\":%s%.2f,%s"
171 "%s\"pnl_pct\":%s%.2f,%s"
172 "%s\"tx_fees\":%s%.2f,%s"
173 "%s\"borrow_interest\":%s%.2f%s"
176 "%s\"total\":%s%ld,%s"
177 "%s\"winning\":%s%ld,%s"
178 "%s\"losing\":%s%ld,%s"
179 "%s\"win_rate\":%s%.2f,%s"
180 "%s\"max_win\":%s%.2f,%s"
181 "%s\"max_loss\":%s%.2f,%s"
182 "%s\"avg_pnl\":%s%.2f,%s"
183 "%s\"pnl_stdev\":%s%.2f,%s"
184 "%s\"stop_loss_exits\":%s%ld,%s"
185 "%s\"take_profit_exits\":%s%ld%s"
187 "%s\"performance\":%s{%s"
188 "%s\"max_drawdown\":%s%.4f,%s"
189 "%s\"sharpe_ratio\":%s%.4f,%s"
190 "%s\"sortino_ratio\":%s%.4f,%s"
191 "%s\"calmar_ratio\":%s%.4f%s"
198 indent2, space, pnl, nl,
199 indent2, space, pnl_pct, nl,
207 indent2, space, win_rate, nl,
208 indent2, space, stats->
max_win, nl,
209 indent2, space, stats->
max_loss, nl,
210 indent2, space, avg_pnl, nl,
211 indent2, space, pnl_stdev, nl,
230 offset += snprintf(result + offset, 16384 - offset,
231 ",%s%s\"positions\":%s[", nl, indent1, space);
234 if (i > 0) offset += snprintf(result + offset, 16384 - offset,
",");
235 offset += snprintf(result + offset, 16384 - offset,
236 "%s%s{%s\"symbol\": \"%s\",%s\"quantity\": %.4f,%s\"value\": %.2f,%s\"last_price\": %.2f%s}",
245 offset += snprintf(result + offset, 16384 - offset,
246 "%s%s]", nl, indent1);
248 offset += snprintf(result + offset, 16384 - offset,
"%s}", nl);
278 for (
int i = 0; i < stats->
capacity; i++) {
297 if (!stats)
return NULL;
305 stats->initial_cash = initial_cash;
306 stats->current_cash = initial_cash;
307 stats->portfolio_value = initial_cash;
309 stats->accum_tx_fees = 0.0;
310 stats->accum_borrow_interest = 0.0;
311 stats->total_trades = 0;
312 stats->winning_trades = 0;
313 stats->losing_trades = 0;
314 stats->stop_loss_exits = 0;
315 stats->take_profit_exits = 0;
316 stats->total_profit = 0.0;
317 stats->total_loss = 0.0;
318 stats->max_win = 0.0;
319 stats->max_loss = 0.0;
320 stats->accum_pnl = 0.0;
321 stats->symbols = NULL;
322 stats->quantities = NULL;
323 stats->values = NULL;
324 stats->last_prices = NULL;
325 stats->num_assets = 0;
#define wu_indicator_get(indicator)
Get the current value of the indicator.
#define wu_indicator_delete(indicator)
Delete the indicator and free any resources allocated by it.
#define wu_indicator_update(indicator, value)
Header file for technical indicators.
WU_StDev wu_stdev_new(int dof)
Creates a new standard deviation indicator.
WU_Mean wu_mean_new(void)
Creates a new WU_Mean indicator.
WU_MaxDrawdown wu_max_drawdown_new(void)
Creates a new WU_MaxDrawdown indicator.
static char * stats_to_json(struct WU_PortfolioStats_ *stats, bool pretty)
static char * stats_to_keyvalue(struct WU_PortfolioStats_ *stats)
static void stats_free(struct WU_PortfolioStats_ *stats)
static void stats_update_position(struct WU_PortfolioStats_ *stats, int asset_index, const char *symbol, double quantity, double value, double last_price)
WU_PortfolioStats wu_portfolio_stats_new(double initial_cash, double risk_free_rate)
Creates a new WU_PortfolioStats instance.
static void stats_reset(struct WU_PortfolioStats_ *stats)
static void stats_update(struct WU_PortfolioStats_ *stats, double cash, double portfolio_value, WU_TimeStamp timestamp)
static char * wu_strdup(const char *s)
static void stats_record_trade(struct WU_PortfolioStats_ *stats, double pnl, WU_CloseReason reason)
WU_CalmarRatio wu_calmar_ratio_new(double initial_value)
WU_SharpeRatio wu_sharpe_ratio_new(double initial_value, double risk_free_rate)
Creates a new Sharpe Ratio calculator.
WU_SortinoRatio wu_sortino_ratio_new(double initial_value, double risk_free_rate)
Creates a new Sortino Ratio calculator.
WU_PortfolioStats tracks portfolio state, positions, and trading statistics.
int64_t take_profit_exits
WU_SortinoRatio sortino_ratio
WU_MaxDrawdown max_drawdown
WU_SharpeRatio sharpe_ratio
WU_CalmarRatio calmar_ratio
double accum_borrow_interest
A timestamp represent a mark in time given relative to unix epoch.
WU_CloseReason
WU_CloseReason represents the reason for closing a position, which can be a trading signal,...
@ WU_CLOSE_REASON_TAKE_PROFIT
@ WU_CLOSE_REASON_STOP_LOSS