kestrel.markets
Version:
A typed, token-efficient language + runtime for agentic trading: agents author bounded plans, the runtime fires them at the tick. CLI + typed library + MCP server.
42 lines (41 loc) • 2.02 kB
JavaScript
/** Column count for the price axis. A layout constant (not a value); wide enough to *see*
* drift/range-walls as block migration, narrow enough to stay token-cheap. */
export const TAPE_WIDTH = 40;
/** The tape's price axis bounds — the data's OWN extremes: `lo` = min over every row's low/open/close,
* `hi` = max over every row's high/open/close. The axis is derived, never invented. PURE. */
export function tapeBounds(rows) {
let lo = Infinity;
let hi = -Infinity;
for (const r of rows) {
lo = Math.min(lo, r.low, r.open, r.close);
hi = Math.max(hi, r.high, r.open, r.close);
}
return { lo, hi };
}
/**
* One row's rotated candle over `[lo, hi]`: a `─` wick spanning low→high and a `█` body spanning
* open→close, positioned by price → column. A flat window (`span <= 0`) collapses to a single block
* column; a zero-width body still shows one block. Trailing spaces are trimmed (the leading indent —
* the low column — is kept: it encodes price level). Returns ONLY the candle cells; the caller owns
* the row prefix (clock/indent) and the header. PURE.
*/
export function candleLine(row, lo, hi, width = TAPE_WIDTH) {
const span = hi - lo;
const colOf = (p) => {
if (span <= 0)
return 0; // flat window: one column
const c = Math.round(((p - lo) / span) * (width - 1));
return c < 0 ? 0 : c > width - 1 ? width - 1 : c;
};
const loCol = colOf(row.low);
const hiCol = colOf(row.high);
const bodyLo = Math.min(colOf(row.open), colOf(row.close));
const bodyHi = Math.max(colOf(row.open), colOf(row.close));
const cells = Array(width).fill(" ");
for (let c = loCol; c <= hiCol; c += 1)
cells[c] = "─"; // wick low→high
for (let c = bodyLo; c <= bodyHi; c += 1)
cells[c] = "█"; // body open→close
cells[bodyLo] = "█"; // a zero-width body still shows one block
return cells.join("").replace(/\s+$/, ""); // keep leading indent, trim trailing
}