
Custom Indicator
- 390 installs
- 13 repo stars
- Updated June 12, 2026
- marketcalls/openalgo-indicator-skills
custom-indicator is an agent skill that scaffolds production-grade OpenAlgo technical indicators from Rust-core ta primitives and vectorized NumPy for developers who need backtest-safe signal logic.
About
custom-indicator is a Claude Code skill in marketcalls/openalgo-indicator-skills that authors custom technical indicators by composing OpenAlgo Rust-core ta primitives with vectorized NumPy. The skill reads indicator-expert rules, accepts an indicator name argument such as zscore, squeeze, vwap-bands, or custom-rsi, and generates O(n) indicator functions with charting and benchmarking hooks. Developers reach for custom-indicator when building algorithmic trading strategies that need correct inputs, outputs, signal logic, and backtest-safe calculations beyond built-in indicators. Allowed tools include Read, Write, Edit, Bash, Glob, and Grep for inspecting rules and writing indicator modules.
- Indicator parameter design
- Signal and plot definitions
- OpenAlgo API conventions
- Backtest-safe calculations
- Reusable strategy primitives
Custom Indicator by the numbers
- 390 all-time installs (skills.sh)
- +21 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #275 of 1,106 Finance & Trading skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/marketcalls/openalgo-indicator-skills --skill custom-indicatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 390 |
|---|---|
| repo stars | ★ 13 |
| Last updated | June 12, 2026 |
| Repository | marketcalls/openalgo-indicator-skills ↗ |
How do you build custom OpenAlgo indicators with NumPy?
Author custom OpenAlgo trading indicators with correct inputs, outputs, signal logic, and backtest-safe calculations for algorithmic strategies.
Who is it for?
Quant developers and algo engineers implementing custom signals on OpenAlgo with NumPy and Rust-core ta primitives.
Skip if: Developers who only need prebuilt indicators without custom signal logic or who are not using the OpenAlgo trading stack.
When should I use this skill?
A developer asks to create, extend, or benchmark a custom technical indicator for OpenAlgo algorithmic strategies.
What you get
O(n) indicator Python functions, signal logic modules, charting hooks, and benchmark-ready calculations
- Custom indicator function
- Signal logic module
- Benchmark-ready calculation code
By the numbers
- Generates O(n) indicator functions from Rust-core ta primitives
- Allowed-tools list includes Read, Write, Edit, Bash, Glob, and Grep
Files
Create a custom technical indicator by composing openalgo's Rust-core ta primitives with vectorized NumPy.
Arguments
$0= indicator name (e.g., zscore, squeeze, vwap-bands, custom-rsi, mean-reversion). Required.
If no arguments, ask the user what indicator they want to build.
Instructions
1. Read the indicator-expert rules, especially:
rules/custom-indicators.md— NumPy + ta-primitive patterns and templatesrules/performance.md— Rust core performance, O(n) guarantees, benchmarkingrules/indicator-catalog.md— Check if indicator already exists in openalgo.ta
2. Check first: If the indicator already exists in openalgo.ta (100+ indicators), tell the user and show the existing API 3. Create custom_indicators/{indicator_name}/ directory (on-demand) 4. Create {indicator_name}.py with:
File Structure
"""
{Indicator Name} — Custom Indicator
Description: {what it measures}
Category: {trend/momentum/volatility/volume/oscillator}
"""
import numpy as np
import pandas as pd
from openalgo import ta
# --- Core Computation (vectorized NumPy on ta primitives) ---
def _compute_{name}(arr: np.ndarray, period: int) -> np.ndarray:
"""Vectorized core computation built on Rust-core primitives."""
n = len(arr)
result = np.full(n, np.nan)
# Compose from ta primitives (they run in Rust):
# mean = ta.sma(arr, period); std = ta.stdev(arr, period); ...
# then combine with NumPy array math (np.where, masks)
return result
# --- Public API ---
def {name}(data, period=20):
"""
{Indicator Name}
Args:
data: Close prices (numpy array, pandas Series, or list)
period: Lookback period (default: 20)
Returns:
Same type as input with indicator values
"""
if isinstance(data, pd.Series):
idx = data.index
result = _compute_{name}(data.values.astype(np.float64), period)
return pd.Series(result, index=idx, name="{Name}({period})")
arr = np.asarray(data, dtype=np.float64)
return _compute_{name}(arr, period)5. Create chart.py for visualization:
"""Chart the custom indicator with Plotly."""
import os
from pathlib import Path
from datetime import datetime, timedelta
from dotenv import find_dotenv, load_dotenv
from openalgo import api, ta
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from {indicator_name} import {name}
# ... fetch data, compute indicator, create chart ...6. Create benchmark.py for performance testing (no warmup needed — the Rust core runs at full speed from the first call):
"""Benchmark the custom indicator."""
import numpy as np
import time
from {indicator_name} import {name}
for size in [10_000, 100_000, 500_000]:
data = np.random.randn(size).cumsum() + 1000
t0 = time.perf_counter()
_ = {name}(data, 20)
elapsed = (time.perf_counter() - t0) * 1000
print(f"{size:>10,} bars: {elapsed:>8.2f}ms")NumPy Rules (CRITICAL)
MUST DO
- Compose from
taprimitives wherever possible — they run in the Rust core np.full(n, np.nan)to initialize output arrays- Vectorize with array expressions,
np.where, and boolean masks - Guard divisions:
np.errstate(invalid="ignore", divide="ignore")plus a safe denominator mask - Respect NaN warm-up periods from the primitives (mask on
~np.isnan(...)) - Float64 for all numeric arrays
- O(n) algorithms only
MUST NOT
- Never reimplement an indicator that already exists in
openalgo.ta - Never write per-bar Python loops over large arrays — vectorize instead
- Never divide without masking zero/NaN denominators
- If the indicator is genuinely path-dependent (sequential state no primitive covers), check whether
ta.ema/ Wilder-style primitives already provide the recursion first; a plain Python loop is a last resort — keep it O(n) and document the trade-off
Available Building Blocks
Public ta methods that run in the Rust core:
from openalgo import ta
# Rolling math: ta.sma, ta.ema, ta.wma, ta.stdev, ta.highest, ta.lowest
# Price action: ta.true_range, ta.atr, ta.change, ta.roc
# Bands/channels: ta.bbands, ta.keltner, ta.donchian
# Signals: ta.crossover, ta.crossunder, ta.exrem, ta.rising, ta.fallingCommon Custom Indicator Patterns
| Pattern | Implementation |
|---|---|
| Z-Score | (value - rolling_mean) / rolling_stdev |
| Squeeze | Bollinger inside Keltner channel |
| VWAP Bands | VWAP + N * rolling stdev of (close - vwap) |
| Momentum Score | Weighted sum of RSI + MACD + ADX conditions |
| Mean Reversion | Distance from SMA as % + threshold |
| Range Filter | ATR-based dynamic filter on close |
| Trend Strength | ADX + directional movement composite |
Example Usage
/custom-indicator zscore /custom-indicator squeeze-momentum /custom-indicator vwap-bands /custom-indicator range-filter
Related skills
How it compares
Choose custom-indicator when you need new OpenAlgo signal logic composed from ta primitives rather than configuring existing chart indicators.
FAQ
What stack does custom-indicator use?
custom-indicator builds OpenAlgo indicators by composing Rust-core ta primitives with vectorized NumPy. The skill follows indicator-expert rules to produce O(n) functions with charting and benchmarking support for algorithmic strategies.
What indicator names can custom-indicator accept?
custom-indicator takes a required indicator-name argument such as zscore, squeeze, vwap-bands, custom-rsi, or mean-reversion. If no name is provided, the skill asks which indicator the developer wants before generating code.