update return calculations
This commit is contained in:
parent
ea7f07e6c1
commit
1e8174e637
2 changed files with 21 additions and 38 deletions
|
|
@ -14,8 +14,8 @@
|
||||||
.hash = "httpz-0.0.0-PNVzrBtMBwAPcQx3mNEgat3Xbsynw-eIC9SmOX5M9XtP",
|
.hash = "httpz-0.0.0-PNVzrBtMBwAPcQx3mNEgat3Xbsynw-eIC9SmOX5M9XtP",
|
||||||
},
|
},
|
||||||
.zfin = .{
|
.zfin = .{
|
||||||
.url = "git+https://git.lerch.org/lobo/zfin#ecadfb492d8730c3226c738b6cb63e688d7f89dc",
|
.url = "git+https://git.lerch.org/lobo/zfin#2ac4156bc1227ca7691a22a35411ff77064ae697",
|
||||||
.hash = "zfin-0.0.0-J-B21tqwDACaht3HgLXCYDXJsyZsMwzncEKeX2JYiiJG",
|
.hash = "zfin-0.0.0-J-B21razDADDEOFs3alWrMtStAaULKO7H6Et1ViNwkpr",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/main.zig
55
src/main.zig
|
|
@ -137,14 +137,17 @@ fn handleReturns(app: *App, req: *httpz.Request, res: *httpz.Response) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const candle_result = app.svc.getCandles(symbol) catch {
|
const result = app.svc.getTrailingReturns(symbol) catch {
|
||||||
res.status = 404;
|
res.status = 404;
|
||||||
res.body = "Symbol not found or fetch failed";
|
res.body = "Symbol not found or fetch failed";
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
defer app.allocator.free(candle_result.data);
|
defer app.allocator.free(result.candles);
|
||||||
const candles = candle_result.data;
|
if (result.dividends) |divs| {
|
||||||
|
defer zfin.Dividend.freeSlice(app.allocator, divs);
|
||||||
|
}
|
||||||
|
|
||||||
|
const candles = result.candles;
|
||||||
if (candles.len == 0) {
|
if (candles.len == 0) {
|
||||||
res.status = 404;
|
res.status = 404;
|
||||||
res.body = "No candle data";
|
res.body = "No candle data";
|
||||||
|
|
@ -152,19 +155,24 @@ fn handleReturns(app: *App, req: *httpz.Request, res: *httpz.Response) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
const last_close = candles[candles.len - 1].close;
|
const last_close = candles[candles.len - 1].close;
|
||||||
|
|
||||||
// Price-only returns (from adjusted close)
|
|
||||||
const price_ret = zfin.performance.trailingReturns(candles);
|
|
||||||
var date_buf: [10]u8 = undefined;
|
var date_buf: [10]u8 = undefined;
|
||||||
const date_str = candles[candles.len - 1].date.format(&date_buf);
|
const date_str = candles[candles.len - 1].date.format(&date_buf);
|
||||||
const risk = zfin.risk.trailingRisk(candles);
|
|
||||||
|
|
||||||
const p1y = if (price_ret.one_year) |r| r.annualized_return else null;
|
// Price-only returns (from adjusted close)
|
||||||
const p3y = if (price_ret.three_year) |r| r.annualized_return else null;
|
const p1y = if (result.asof_price.one_year) |r| r.annualized_return else null;
|
||||||
const p5y = if (price_ret.five_year) |r| r.annualized_return else null;
|
const p3y = if (result.asof_price.three_year) |r| r.annualized_return else null;
|
||||||
const p10y = if (price_ret.ten_year) |r| r.annualized_return else null;
|
const p5y = if (result.asof_price.five_year) |r| r.annualized_return else null;
|
||||||
|
const p10y = if (result.asof_price.ten_year) |r| r.annualized_return else null;
|
||||||
|
|
||||||
|
// Total returns (best of adj_close and dividend reinvestment)
|
||||||
|
const total = result.asof_total orelse result.asof_price;
|
||||||
|
const t1y = if (total.one_year) |r| r.annualized_return else null;
|
||||||
|
const t3y = if (total.three_year) |r| r.annualized_return else null;
|
||||||
|
const t5y = if (total.five_year) |r| r.annualized_return else null;
|
||||||
|
const t10y = if (total.ten_year) |r| r.annualized_return else null;
|
||||||
|
|
||||||
// Per-period volatility
|
// Per-period volatility
|
||||||
|
const risk = zfin.risk.trailingRisk(candles);
|
||||||
const v1y = if (risk.one_year) |r| r.volatility else null;
|
const v1y = if (risk.one_year) |r| r.volatility else null;
|
||||||
const v3y = if (risk.three_year) |r| r.volatility else null;
|
const v3y = if (risk.three_year) |r| r.volatility else null;
|
||||||
const v5y = if (risk.five_year) |r| r.volatility else null;
|
const v5y = if (risk.five_year) |r| r.volatility else null;
|
||||||
|
|
@ -174,31 +182,6 @@ fn handleReturns(app: *App, req: *httpz.Request, res: *httpz.Response) !void {
|
||||||
const vol_best = v10y orelse v5y orelse v3y orelse v1y;
|
const vol_best = v10y orelse v5y orelse v3y orelse v1y;
|
||||||
const vol_term: ?u8 = if (v10y != null) 10 else if (v5y != null) 5 else if (v3y != null) 3 else if (v1y != null) 1 else null;
|
const vol_term: ?u8 = if (v10y != null) 10 else if (v5y != null) 5 else if (v3y != null) 3 else if (v1y != null) 1 else null;
|
||||||
|
|
||||||
// Total returns: adj_close is the primary source (accounts for splits + dividends).
|
|
||||||
// Dividend-reinvestment only fills gaps where adj_close returns null
|
|
||||||
// (e.g. stable-NAV funds with short candle history).
|
|
||||||
var t1y: ?f64 = p1y;
|
|
||||||
var t3y: ?f64 = p3y;
|
|
||||||
var t5y: ?f64 = p5y;
|
|
||||||
var t10y: ?f64 = p10y;
|
|
||||||
|
|
||||||
if (app.svc.getDividends(symbol)) |div_result| {
|
|
||||||
defer zfin.Dividend.freeSlice(app.allocator, div_result.data);
|
|
||||||
const total = zfin.performance.trailingReturnsWithDividends(candles, div_result.data);
|
|
||||||
if (t1y == null) if (total.one_year) |r| {
|
|
||||||
t1y = r.annualized_return;
|
|
||||||
};
|
|
||||||
if (t3y == null) if (total.three_year) |r| {
|
|
||||||
t3y = r.annualized_return;
|
|
||||||
};
|
|
||||||
if (t5y == null) if (total.five_year) |r| {
|
|
||||||
t5y = r.annualized_return;
|
|
||||||
};
|
|
||||||
if (t10y == null) if (total.ten_year) |r| {
|
|
||||||
t10y = r.annualized_return;
|
|
||||||
};
|
|
||||||
} else |_| {}
|
|
||||||
|
|
||||||
// Check if XML requested
|
// Check if XML requested
|
||||||
if (q.get("fmt")) |fmt| {
|
if (q.get("fmt")) |fmt| {
|
||||||
if (std.ascii.eqlIgnoreCase(fmt, "xml")) {
|
if (std.ascii.eqlIgnoreCase(fmt, "xml")) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue