GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • TA-Lib.org
  • Install
  • Docs
  • About Us
  • PrevJava Core API

This view

  • Original page
  • New address

GeezerVison is showing ta-lib.org — Java Streaming API

Java Streaming API


The streaming API is built for live feeds: open a stream once, then feed it one bar at a time. The stream carries its state from bar to bar, so a new bar never costs a pass over the history.

Every value is bit-identical to what the batch method would return by recomputing over the whole array (see detailed specs for a few exceptions).

Each streamable function adds two factory methods on Core and a handful of methods on its stream (a class nested in Core, e.g. Core.SmaStream — unrelated to java.util.stream):

CallWhenDoes
core.<name>Open(history, params)oncevalidate params, consume warm-up history, return a stream
stream.update(bar)once per closed barcommit one bar and answer the new value
stream.peek(bar)any time on the forming barevaluate a provisional bar without committing

A single-output function answers with a double (or an int for a candlestick pattern) return. A multi-output one writes into a sink you pass and own — see Multi-input / multi-output.

One more call, openAndFill, writes array output instead of a single value — see Array-Fill Open below.

Additional utility functions are available.

There is no close — a stream is ordinary heap state, so an unreferenced stream is simply garbage-collected.

Example (SMA)

import io.github.talib.Core;

Core core = Core.DEFAULT;

// Seed with warm-up history (>= smaLookback(period) + 1 bars).
double[] history = /* ...your closing prices... */;
Core.SmaStream s = core.smaOpen(history, 30); // value() starts at the last history bar

// Each time a bar closes:
double v = s.update(newClose);                  // throws on a non-finite bar, or past INDEX_MAX

// Intra-bar, on the not-yet-closed bar (repeat as the price ticks):
double provisional = s.peek(formingClose);      // state left unchanged

open returns the stream directly; its value() starts at the last history bar's value. After a successful open, what update and peek reject is invalid input such as NaN or ±Inf; update also rejects a bar past Core.INDEX_MAX, the last index the batch API addresses. A rejection changes nothing at all — no state, no value, and no range. To count a rejected bar rather than re-feed it, call advance(); value() then answers the value(s) at the last bar the stream counted (see Utility Calls).

Rules

  • Warm-up. open succeeds only if history.length >= <name>Lookback(params) + 1 — with fewer bars there is no defined value yet. Too little history throws InsufficientHistoryException (see Error model). After open, the history can be discarded — the stream keeps everything it needs.
  • Closed vs forming bar. update commits state irreversibly, so use it only for closed bars. peek returns exactly the value the next update would, without committing — call it as often as the forming bar ticks. value() re-reads the last committed value without recomputing.
  • The unstable period is resolved once, at open. The lookback above is the one of the Core the stream is opened on. Under an Auto level it is the Auto lookback, so open needs that many bars plus one.
  • Parameters are fixed at open. Changing a parameter means a new stream. Unstable period and candle settings are read from the owning Core at open. Since Core is immutable they cannot change underneath a live stream — to stream with different settings, build a new Core and open from that.
  • Threads. A stream is single-writer: update must not race with any other call on the same stream. Processing forks are possible by cloning the stream, and each clone becomes fully independent and can be updated concurrently.

Multi-input / multi-output

Inputs and outputs mirror the batch method. A multi-output function writes its outputs into a Core.<Name>Out — a plain mutable object with one public field per output, in batch output order — that you allocate and pass in. Candlestick patterns return int:

// MACD: one input, three outputs
Core.MacdStream m = core.macdOpen(history, 12, 26, 9);
Core.MacdOut out = new Core.MacdOut();   // allocate once, reuse every bar
m.update(newClose, out);
// out.macd, out.macdSignal, out.macdHist

// A candlestick pattern returns int
Core.CdldojiStream c = core.cdldojiOpen(open, high, low, close);
int pattern = c.update(o, h, l, cl);

Reusing one sink is the point: update, peek and value overwrite its fields rather than allocating a new one. The price is that its contents are only valid until the next call that writes it. It is a buffer, not a reading — a reference kept past that call, or one put in a collection, sees the value change underneath it. Copy the fields out if the reading has to outlive the call, or allocate one sink per slot. For the same reason <Name>Out deliberately has no equals/hashCode: value equality on a mutable object breaks HashMap/HashSet the moment a reused sink becomes a key. Passing null is an IllegalArgumentException, taken before the bar is committed.

Array-Fill Open

open and update each write a single value. One more call writes a full array instead — the same shape the batch method would produce — while still opening the stream:

CallWhenDoes
core.<name>OpenAndFill(..)once, instead of openlike open, but also fills the output for every history bar
import io.github.talib.OutRange;

double[] warmup = new double[history.length];

Core.SmaStream s = core.smaOpenAndFill(history, 30, warmup);
OutRange r = s.outRange();                      // the bars it has an output for

// warmup[0 .. r.count() - 1] is the SMA over all of history; then stream on:
double v = s.update(newClose);

The optional parameters and output arrays are exactly the batch method's. The range written is reported on the returned stream as outRange() rather than through out-parameters — see Utility Calls below. The output arrays must not alias the input or each other.

Utility Calls

CallWhenDoes
stream.value() / stream.value(out)any timethe value(s) at the last bar the stream counted, without recomputing
stream.clone()any timean independent fork of the stream, at the same bar
stream.outRange()any timethe bars the stream has an output for — the batch range over the same bars
stream.advance()after a bar you will not feedadvances the range without affecting any other internal state of the stream
Core.SmaStream s = core.smaOpen(history, 30);

double v = s.value();               // the value at the last bar s counted
Core.SmaStream fork = s.clone();    // independent from here on
OutRange r = s.outRange();          // the bars s has an output for
s.advance();                        // a bar you skipped, counted

clone() overrides Object.clone() but does not use the Cloneable protocol — the body is a copy constructor, so it needs no marker interface and throws no CloneNotSupportedException.

See Rules for when concurrent reads of these are safe.

Error model

CallBehaviour
<name>Open / <name>OpenAndFillToo little history throws InsufficientHistoryException (a subclass of IllegalArgumentException — catch it to accumulate more bars and retry). Out-of-range parameters throw TALibArgumentException.
update / peek
  • IllegalArgumentException on invalid input such as NaN or ±Inf
  • IndexOutOfBoundsException from update (never peek) once the range has reached bar Core.INDEX_MAX, the last index the batch API addresses
A rejection changes nothing at all — no state, no value, and no range.
advanceIndexOutOfBoundsException once the range has reached bar Core.INDEX_MAX, the last index the batch API addresses.
value() / clone / outRangeNever throw. value(out) throws IllegalArgumentException on a null sink, as update and peek do.

Discovering streamable functions

When driving TA-Lib through the Abstract API, streamable functions carry the FuncFlags.STREAMING bit in FuncInfo#flags().

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.