Documentation/ChipaFlow Reference

ChipaFlow Language Reference

ChipaFlow is the .chipa strategy language — a small, strict DSL for trading logic. Exact-decimal floats, indicators as first-class values, crossover operators built into the grammar, and one source that compiles to either a positions target (stock) or a fixed-payout target (binary).

The minimum program

Only main is required, and its signature is fixed:

func main(candle: Candle, ctx: Context) -> TradeAction { Hold }

Rules that catch most new code

  • Names are case-typed. snake_case for values and functions; PascalCase for types, variants, and indicators. let Foo = 1; is a parse error.
  • No truthiness. Conditions must be boolif 1 {} is an error.
  • No implicit numeric conversion. int and float never mix; write x as float.
  • if is an expression. Both branches must produce the same type. As a statement it needs a trailing ;.
  • Construction uses =, not :P { a = 1.0 }. Colons only annotate types.
  • Indicator instances live in top-level lets and are only readable inside functions.
  • Floats are exact decimals. 0.1 + 0.2 == 0.3 holds. Literals need digits on both sides of the dot: 1.0, never 1.
  • Prefer bare Buy / Sell / Hold — setting an amount compiles but warns (E0332).
  • Statements end in ;; a block's last expression is its value; return is only for early exit.

Types

TypeLiteralsNotes
int0, -14, 1_000128-bit, overflow traps
float1.5, 2.5e3, 50bpexact decimal; 50bp = 0.005
booltrue, false
string"close"+ concatenates
Array<T>[1.0, 2.0]immutable, indexable, no methods
range0..n, 0..=nfor-iterable
Window<T>Window(64)a value — write back on push
Tensor<f32>via std.tensor.*IEEE f32 — the exact-decimal carve-out

Indicators

Declared once at the top level, read inside functions. Crossovers are language operators: a >^ b is true on the candle where a crosses above b; a <^ b the reverse.

let fast = Sma(9);
let slow = Sma(21);
let rsi = Rsi(14);
let bb = Bb(20, 2.0);       # Bands: .upper .middle .lower
let macd = Macd(12, 26, 9); # MacdOut: .macd .signal .histogram

func main(candle: Candle, ctx: Context) -> TradeAction {
    if fast >^ slow && rsi < 70.0 { Buy }
    else if fast <^ slow { Sell }
    else { Hold }
}

Built-ins include Sma, Ema, Wma, Smma, Rsi, Atr, Roc, Momentum, Highest/Lowest, WilliamsR, Obv, Lag, Bb, Kc, Stoch, Macd, Alligator, SuperTrend, and the stream sources Aggregate and WaveletDenoise.

Two targets, one language

target = "stock"target = "binary"
Market modelpositions — main opens, @trade managesfixed-payout bets that settle at expiry
Context extrasctx.position()ctx.payout()
Canonical actionsBuy / SellCall / Put
Per-trade handler@tradeTradeCommand

On the stock target a @trade handler runs once per open trade, per candle. Qualify every command — bare Hold is TradeAction.Hold and will not type-check in a handler:

@trade func manage(trade: TradeContext, c: Candle) -> TradeCommand {
    if trade.stop_loss() == 0.0 {
        # 0 means "unchanged", so this brackets the trade exactly once.
        TradeCommand.Update {
            stop_loss = trade.entry() * 0.97,
            take_profit = trade.entry() * 1.05,
        }
    } else if trade.bars() > 10 && trade.profit() < 0.0 {
        TradeCommand.Close
    } else {
        TradeCommand.Hold
    }
}

Where to go next