← 모든 예제
예제 29
Custom indicator
a custom indicator written in T0: an EMA of the chart's closes drawn as a line on the chart, and a mark where a
- 분류
- Workspace: 차트와 패널을 읽거나 변경
- 권한
- market.readworkspace.readworkspace.write
- 실행하기 전에
- a terminal window with a chart on a timeframe the backend keeps candles for (1m, 5m, 15m, 30m, 1h, 4h, 1D)
- 하는 일
- DRAWS on the active chart: one line and the crossing marks, named "ema_cross". Delete them with plot.clear.
- 실행 방법
- open the T0 Editor, grant market.read, workspace.read and workspace.write, Run. Attach it to a "Timeframe changes"
- 언어
>=0.1.1, <0.2.0- 호스트
>=0.1.6, <0.2.0- 필요한 것
- market >=0.1.2, <0.2.0workspace >=0.1.0, <0.2.0plot >=0.1.0, <0.2.0
소스
// Purpose: a custom indicator written in T0: an EMA of the chart's closes drawn as a line on the chart, and a mark where a // fast EMA crosses a slow one. Run it again and it replaces its own drawing; nothing a person drew is touched. // Category: workspace // Permissions: market.read, workspace.read, workspace.write // Preconditions: a terminal window with a chart on a timeframe the backend keeps candles for (1m, 5m, 15m, 30m, 1h, 4h, 1D) // Side effects: DRAWS on the active chart: one line and the crossing marks, named "ema_cross". Delete them with plot.clear. // Run: open the T0 Editor, grant market.read, workspace.read and workspace.write, Run. Attach it to a "Timeframe changes" // hook (Script Hooks) to keep it on every chart you switch. lang ">=0.1.1, <0.2.0"; host "ttt" ">=0.1.6, <0.2.0"; requires "market" ">=0.1.2, <0.2.0"; requires "workspace" ">=0.1.0, <0.2.0"; requires "plot" ">=0.1.0, <0.2.0"; import std.ind; const OWNER: String = "ema_cross"; // The value at an index, whether the index is past the series or the indicator has not warmed up yet. fn at(xs: List<Option<Float>>, i: Int) -> Option<Float> { let found = match xs.get(i) { Some(value) => value, None => None, }; return found; } // How far the fast line is above the slow one at an index (None until both have a value). fn gap(fast: List<Option<Float>>, slow: List<Option<Float>>, i: Int) -> Option<Float> { let found = match at(fast, i) { Some(f) => match at(slow, i) { Some(s) => Some(f - s), None => None, }, None => None, }; return found; } fn main() -> Result<Unit, Error> { let chart = workspace.active_chart().expect("no chart is open"); // Only closed candles: a bar that can still change is never given to a program. let candles = market.chart_candles(chart.symbol, chart.timeframe, 500)?; let mut closes: List<Float> = []; for c in candles { closes.push(to_float(c.close.amount())); } let fast = ind.ema(closes, 9); let slow = ind.ema(closes, 21); plot.clear(chart.chart, OWNER)?; let mut points: List<plot.Point> = []; let mut crossings = 0; let mut i = 0; while i < candles.len() { let candle = candles.get(i).expect("a candle"); match at(slow, i) { Some(value) => { points.push(plot.Point { time: candle.open_time, price: price(decimal_from_float(value, 2), candle.close.currency()) }); } None => {} } // Crossed: the fast line was at or below the slow one on the previous bar and is above now, or the reverse. if i > 0 { match gap(fast, slow, i - 1) { Some(before) => { match gap(fast, slow, i) { Some(now) => { if before <= 0.0 && now > 0.0 { plot.marker(chart.chart, OWNER, candle.open_time, candle.low, "▲ cross up", "green")?; crossings = crossings + 1; } if before >= 0.0 && now < 0.0 { plot.marker(chart.chart, OWNER, candle.open_time, candle.high, "▼ cross down", "red")?; crossings = crossings + 1; } } None => {} } } None => {} } } i = i + 1; } plot.line(chart.chart, OWNER, points, "EMA 21", "#ff8000")?; print(chart.symbol + " " + chart.timeframe + ": " + to_string(candles.len()) + " candles, EMA 21 drawn, " + to_string(crossings) + " crossings marked"); return Ok(()); }