Visualization with Kino TheoryCraft
Kino TheoryCraft is a visualization library for TheoryCraft that renders interactive trading charts in Livebook notebooks. It is built on TradingView Lightweight Charts, a JavaScript library for financial charting.
This library is a visualization tool. It displays market data (bars, indicators) produced by TheoryCraft pipelines. It does not execute strategies or manage portfolios.
⚠️ Kino TheoryCraft is under active development. The API may change.
Installation
Add to your Livebook notebook:
Mix.install([
{:kino_theory_craft, github: "theorycraft-trading/kino_theory_craft"},
{:theory_craft, github: "theorycraft-trading/theory_craft"},
# Also your DataFeed if needed
{:dukascopy, github: "theorycraft-trading/dukascopy"}
])Modules
The library provides two main modules:
| Module | Purpose |
|---|---|
KinoTheoryCraft.Chart | Build chart configurations with series and options |
KinoTheoryCraft.LiveChart | Render charts with real-time update capabilities |
Chart Module
KinoTheoryCraft.Chart provides a fluent API for building chart configurations.
Creating a Chart
alias KinoTheoryCraft.Chart
chart = Chart.new(width: :auto, height: 600)The new/1 function creates a chart struct with optional width and height.
Attaching a Data Source
Use set_source/2 to attach a MarketSource or any enumerable:
chart = Chart.set_source(chart, market_source)The source provides data that series can reference by name.
Adding Series
The add_data_from_source/4 function adds a series that loads data lazily from the attached source:
chart =
chart
|> Chart.add_data_from_source("EURUSD", :candlestick)
|> Chart.add_data_from_source("SMA_20", :line)
|> Chart.add_data_from_source("RSI", :line, pane: 1, options: %{color: "#2962ff"})Parameters:
- First argument: the data name in the source
- Second argument: the series type
- Options:
paneindex andoptionsfor series styling
For pre-computed data, use add_data/5:
data = [
%{time: ~U[2024-01-01 00:00:00Z], open: 1.10, high: 1.11, low: 1.09, close: 1.105},
%{time: ~U[2024-01-01 00:05:00Z], open: 1.105, high: 1.12, low: 1.10, close: 1.115}
]
chart = Chart.add_data(chart, "EURUSD", :candlestick, data)For empty series that will receive live updates, use add_series/4:
chart = Chart.add_series(chart, "EURUSD", :candlestick)Series Types
| Type | Description | Data Format |
|---|---|---|
:candlestick | OHLC candlestick bars | %{time, open, high, low, close} |
:bar | OHLC bar chart | %{time, open, high, low, close} |
:line | Simple line | %{time, value} |
:area | Filled area under line | %{time, value} |
:histogram | Vertical bars | %{time, value} |
:baseline | Line with fill above/below baseline | %{time, value} |
Styling
Chart and series options follow the Lightweight Charts API. Pass chart_options to Chart.new/1 and options when adding series.
See examples.livemd for practical usage examples.
candlestick_options = %{
up_color: "#00bfff",
down_color: "#683ab6",
border_up_color: "#0288d1",
border_down_color: "#4527a0",
wick_up_color: "#0288d1",
wick_down_color: "#4527a0"
}
chart_options = %{
time_scale: %{time_visible: true, seconds_visible: true}
}
Chart.new(width: :auto, height: 400, chart_options: chart_options)
|> Chart.set_source(market_source)
|> Chart.add_data_from_source("data_m5", :candlestick, options: candlestick_options)Multi-Pane Layout
The pane option organizes series into separate chart sections:
chart =
Chart.new(width: :auto, height: 600)
|> Chart.set_source(market_source)
|> Chart.add_data_from_source("data_m5", :candlestick, pane: 0)
|> Chart.add_data_from_source("sma_20", :line, pane: 0)
|> Chart.add_data_from_source("rsi", :line, pane: 1)
|> Chart.add_data_from_source("volume", :histogram, pane: 2)Pane indices start at 0. Series in the same pane share the same price scale.
Rendering Static Charts
Charts implement the Kino.Render protocol. Simply return a chart from a Livebook cell:
chartOr explicitly render:
Kino.render(chart)LiveChart Module
KinoTheoryCraft.LiveChart renders charts that can receive real-time updates.
Creating a Live Chart
alias KinoTheoryCraft.{Chart, LiveChart}
chart =
Chart.new(width: :auto, height: 600)
|> Chart.add_series("EURUSD", :candlestick)
kino = LiveChart.render(chart)
Kino.render(kino)Updating Data
Replace all data for series:
LiveChart.set_data(kino, %{
"EURUSD" => [
%{time: ~U[2024-01-01 00:00:00Z], open: 1.10, high: 1.11, low: 1.09, close: 1.105},
%{time: ~U[2024-01-01 00:05:00Z], open: 1.105, high: 1.12, low: 1.10, close: 1.115}
]
})Append or update individual points:
LiveChart.update(kino, %{
"EURUSD" => %{time: ~U[2024-01-01 00:10:00Z], open: 1.115, high: 1.12, low: 1.11, close: 1.118}
})The update/2 function also accepts MarketEvent structs from TheoryCraft pipelines.
Control Functions
# Clear all series data
LiveChart.clear(kino)
# Fit chart viewport to visible data
LiveChart.fit_content(kino)Lightweight Charts
Kino TheoryCraft uses TradingView Lightweight Charts for rendering. This JavaScript library provides:
- Performant rendering of financial time series
- Multiple series types (candlestick, line, area, histogram, bar, baseline)
- Price and time scale management
- Crosshair and tooltip functionality
The library handles the JavaScript integration internally. You work with Elixir data structures; the library serializes them to the format Lightweight Charts expects.
Time values are converted from Elixir DateTime structs to Unix timestamps (seconds with millisecond precision).
Livebook Integration
Kino TheoryCraft is built on Kino, the Livebook component framework. It uses:
Kino.JSfor static chart renderingKino.JS.Livefor real-time updates
Charts render automatically in Livebook cells. The JavaScript assets are bundled with the library.
Use Cases Examples
Backtesting Inspection
After running a backtest, visualize the price action:
alias KinoTheoryCraft.Chart
alias TheoryCraft.MarketSource
feed_options = [
instrument: "EUR/USD",
from: ~D[2025-01-01],
to: ~D[2025-01-02]
]
market_source =
%MarketSource{}
|> MarketSource.add_data({Dukascopy.DataFeed, feed_options}, name: "eurusd")
|> MarketSource.resample("m5", bar_only: true, data: "eurusd", name: "eurusd_m5")
Chart.new(width: :auto, height: 400)
|> Chart.set_source(market_source)
|> Chart.add_data_from_source("eurusd_m5", :candlestick)Debugging Strategies
Use visualization to understand why a strategy behaved unexpectedly. Overlay entry/exit signals, indicator values, and price action to identify issues.
Data Exploration
Before building strategies, explore market data visually. Check data quality, identify patterns, and understand market behavior.
Next Steps
- Dukascopy DataFeed Guide - Download historical data for visualization
- MarketSource and DataFeeds - Understand data pipelines
- Lightweight Charts Documentation - Learn about the underlying charting library