Tushare Data
zillionare/zillionare
面向中文自然语言的 Tushare 数据研究技能。用于把“看看这只股票最近怎么样”“帮我查财报趋势”“最近哪个板块最强”“北向资金在买什么”“给我导出一份行情数据”这类请求,转成可执行的数据获取、清洗、对比、筛选、导出与简要分析流程。适用于 A 股、指数、ETF/基金、财务、估值、资金流、公告新闻、板块概念与宏观数据等研究场景。
Build a custom indicator for the OpenAlgo /trading charting terminal (openalgo-charts).
$ npx skills add marketcalls/openalgo --skill chart-indicator -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install marketcalls/openalgo chart-indicator --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/marketcalls/openalgo.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/chart-indicator .claude/skills/chart-indicator && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "chart-indicator" agent skill from https://github.com/marketcalls/openalgo/tree/main/.claude/skills/chart-indicator into .claude/skills/chart-indicator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "chart-indicator", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/marketcalls/openalgo/tree/main/.claude/skills/chart-indicatorType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add marketcalls/openalgo --skill chart-indicator -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install marketcalls/openalgo chart-indicator --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marketcalls/openalgo.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/chart-indicator .agents/skills/chart-indicator && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "chart-indicator" agent skill from https://github.com/marketcalls/openalgo/tree/main/.claude/skills/chart-indicator into .agents/skills/chart-indicator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "chart-indicator", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add marketcalls/openalgo --skill chart-indicator -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install marketcalls/openalgo chart-indicator --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marketcalls/openalgo.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/chart-indicator .cursor/skills/chart-indicator && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "chart-indicator" agent skill from https://github.com/marketcalls/openalgo/tree/main/.claude/skills/chart-indicator into .cursor/skills/chart-indicator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "chart-indicator", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/marketcalls/openalgo.git --path .claude/skills/chart-indicator--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add marketcalls/openalgo --skill chart-indicator -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install marketcalls/openalgo chart-indicator --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marketcalls/openalgo.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/chart-indicator .gemini/skills/chart-indicator && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "chart-indicator" agent skill from https://github.com/marketcalls/openalgo/tree/main/.claude/skills/chart-indicator into .gemini/skills/chart-indicator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "chart-indicator", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install marketcalls/openalgo chart-indicatorInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add marketcalls/openalgo --skill chart-indicator -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/marketcalls/openalgo.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/chart-indicator .github/skills/chart-indicator && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "chart-indicator" agent skill from https://github.com/marketcalls/openalgo/tree/main/.claude/skills/chart-indicator into .github/skills/chart-indicator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "chart-indicator", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add marketcalls/openalgo --skill chart-indicator -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install marketcalls/openalgo chart-indicator --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/marketcalls/openalgo.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/chart-indicator .opencode/skills/chart-indicator && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "chart-indicator" agent skill from https://github.com/marketcalls/openalgo/tree/main/.claude/skills/chart-indicator into .opencode/skills/chart-indicator/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "chart-indicator", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
chart-indicatorBuild a custom indicator for the OpenAlgo /trading charting terminal (openalgo-charts).
Chart Indicator is an agent skill from marketcalls/openalgo. Build a custom indicator for the OpenAlgo /trading charting terminal (openalgo-charts). Use when asked to create, port, or debug a chart indicator, overlay, oscillator, band, or on-chart signal, including porting a study written for another charting platform. Writes a plain-JS descriptor into strategies/indicators/, but only after it validates against the real library. This is the chart path, not the Python openalgo.ta path used from strategies and scanners.
Its SKILL.md is about 8.7k tokens, which your agent loads only when the skill is triggered. The skill folder holds 23 other files (for example `examples/complex_session_vwap.js`, `examples/dashboard_table.js` and `examples/displaced_cloud_zones.js`).
It sits in Business, Finance & HR, covering Trading and backtesting. It works with Python and npm. The repository describes itself as: Open Source Algo Trading Platform for Everyone. The licence is AGPL-3.0.
6 steps, taken from the first numbered list in SKILL.md.
Read from SKILL.md and the folder at commit 6a6f201. It shows what the files ask for, not the result of running them.
Pre-approves these tools, so the agent can use them without asking each time:
ReadWriteEditBashGlobGrepFrom allowed-tools in the SKILL.md frontmatter.
Ships script files (JavaScript, from the files we listed), which the agent can run.
Shell commands in SKILL.md call:
nodenpmgitFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md. Its commands use npm and git, which can reach the network depending on how they are called.
From URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Chart Indicator loads about 8.7k tokens when it runs. Until then it costs about 120 tokens; SKILL.md has 4,841 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check noted patterns worth knowing about, such as sudo or a known installer.
allowed-tools: Read, Write, Edit, Bash, Glob, GrepAutomated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from marketcalls/openalgo at commit 6a6f201, republished under its AGPL-3.0 licence (© marketcalls). 4,841 words, ~8,708 tokens.
.claude/skills/chart-indicator/SKILL.md (or your agent's skills folder). This skill also uses 21 other files; get the full folder from GitHub./tradingBuild an indicator for the charting terminal. It becomes a picker entry with a generated settings dialog, a legend row and saved-layout persistence, with no build step and no restart.
This is the chart (JavaScript) path. It has nothing to do with the Python
openalgo.ta indicators used from strategies, scanners and backtests: different
language, different runtime, different API. If the request is for a Python
indicator, this skill is the wrong one.
Never write a file into strategies/indicators/ directly. That folder is
imported by the live chart, and the runtime fails silently in the ways that
matter most: a column that is one element short, or a plot key that does not
match what calc returns, draws nothing at all and raises nothing anywhere.
Always: write to a scratch path, validate, install on a pass.
# 1. draft to a scratch file (never the indicators folder)
# e.g. <scratchpad>/my_indicator.js
# 2. validate against the real openalgo-charts build
node .claude/skills/chart-indicator/validate.mjs <scratch>/my_indicator.js
# 3. only on PASSED, install it
node .claude/skills/chart-indicator/validate.mjs <scratch>/my_indicator.js --install--install copies into strategies/indicators/ only when there are zero
errors, and exits 1 otherwise. If validation fails, fix the draft and re-run.
Do not install a failing indicator, and do not weaken the validator to get a
pass. Report warnings to the user rather than silently accepting them.
Never run npm install for this. The full frontend tree is 560 MB across
521 packages; the validator needs two ES modules totalling 368 KB. It finds them
itself, in this order: frontend/node_modules/openalgo-charts if a React
developer already has it, then its own .cache/, then it fetches just that one
package at the version pinned in frontend/package.json. openalgo-charts has
zero dependencies, so that is one small download, about a second, cached after.
If the fetch fails (no network, npm unavailable), say so and offer the choice: fix connectivity, or install without the pre-flight check and rely on the chart's own validation, which reports the same structural problems as toasts when the indicator loads. Do not silently skip validation.
The descriptor contract has only gained optional fields since this skill was written, so an existing indicator keeps working on the pinned build. What changed, newest first:
2.5.2 to 2.6.0: seven more built-ins, a timeframe on 29 of them, and a wider descriptor. Every existing descriptor keeps working, and all twelve examples below pass the validator on 2.6.0 unchanged. The index below grew from 387 names to 433 and lost none.
2.6.0. zigzag, high-low-52-week, zlema, vidya, elder-ray,
schaff-trend-cycle and volatility-squeeze take the registry to 112, so a
custom file that already used one of those ids now overrides it (pitfall
13). Twenty-nine built-ins (most averages, the bands, supertrend, atr,
rsi, macd, stochastic, cci, adx and others) gain an input
{ key: 'timeframe', type: 'interval', default: '' }: indicatorDefaults()
of those now includes timeframe: '', their calc folds to a timeframe set
there, and a descriptor that copies their inputs copies a row only their
calc honours (pitfall 24). withTimeframe(descriptor) gives your own study
the same input. Every built-in now rounds a fractional window length (14.5
reads as 15); the exported helpers still do not, so coerce before calling
sma and friends (pitfall 6). An alert's when and message run once for
each bar a pass appended, each seeing the bars and values through the bar it
judges. On a reload, a study whose first pass throws IndicatorInputError
comes back in its error status, while any other throw still stops the
restore. /trading has the chart apply Heikin Ashi, Renko, range bars, line
break, point and figure and Kagi itself, so on those chart types a study's
calc receives the elements drawn with ctx.transformed set, unless the
trader sets its Compute on row to Underlying bars, when it receives the time
bars and its values are read onto the elements; its hooks still run on the
elements, indexed by element (pitfall 20). chart.on is typed from
ChartEventMap: an event of your own is declared into it with
declare module 'openalgo-charts', and chart.emit is deprecated for 3.0.0.
2.5.4 to 2.5.8. Optional fields, all usable here unless noted: an
overlay: true or plot: key target on a draws() shape or a marker, which
is how a study in its own pane puts a signal under the candle's low; font,
size, emphasis and alignment on labels, box captions and marker text;
curve: 'smooth' on a polyline; tooltip, spans and font fields on table
cells, and a tables() hook for several named grids; gradient,
gradientBy and colorBy on a fill; frequency on an alert (all 2.5.4).
New helpers crossesAbove, crossesBelow, crosses, rising and
falling read a missing value as no signal, which is pitfall 4 done for
you. What the library has and /trading does not take is in pitfall 25: the
input types symbol, session, multiline, price and timestamp
(2.5.4), visibleWhen, activeWhen and inline on inputs, and
background returned as a list of targeted columns (2.5.6). 2.5.8 gave
sixteen built-ins a calcTail that a spread does not copy. 2.5.4 and 2.5.5
corrected several calculations around missing data, and HMA at odd lengths,
so a study measured against a built-in re-derives its expectations.
2.5.2, 2.5.3, 2.5.7, 2.5.9 and 2.5.10 changed nothing an indicator
declares. From 2.5.10, text markers on neighbouring bars are laid out in
lanes instead of overlapping, and roc and williams-vix-fix carry new
display names, so match a built-in by id, never by name.
2.5.1: a finished alert can stop drawing its line. Nothing an indicator declares changed and no export was added or removed: the index below counts the same 387 names it counted on 2.5.0.
AlertControllerOptions.spentLines: 'hide' makes a triggered or expired alert
keep everything except its line: the record, the scope, the checkpoints and
the saved runtime all stay, which is what keeps a once-only alert from
re-arming on the next reload. It is opt-in per controller, it is not written
into an alert document, and the default is still 'show'.
A host API, like hovered() and snapPrice() before it. An indicator never
reads it and never declares anything about it.
2.5.0: tables that fit their text. Nothing an indicator declares changed and no export was added or removed: the index below counts the same 387 names it counted on 2.4.8.
The one thing worth knowing for a descriptor: ChartTableOptions.cellWidth
accepts 'auto'. A column then measures itself from its widest cell, using
the font actually drawn, so a per-cell font override or a bold heading is
accounted for rather than guessed at. An empty automatic column keeps a 28 px
minimum, and percentage widths keep their measured proportions. Every cell
also clips its text now, so a long reading can no longer spill over the
column beside it, which is what made a wide value in one row look like a
value in the next.
AlertController.hovered() and Chart.snapPrice(paneIndex, price) also
arrived. Both are host APIs: an indicator never calls either.
2.4.8: grab to pan, and a README rewritten. Nothing an indicator declares changed and no export was added or removed: the index below counts the same 387 names it counted on 2.4.7. Pressing and holding the plot now shows a grabbing hand and pans both axes, and mouse and pen panning stop the moment the pointer is released, while touch keeps its flick. The default covers both axes; a chart with a saved horizontal-only preference keeps it until somebody changes it in the chart navigation settings.
The one thing worth knowing for a descriptor: a clickable legend action
keeps its pointer cursor and stays usable across a repaint, which is the
behaviour a hasSource braces button and a gear depend on. If a legend
action of yours stopped responding after a redraw on an older build, that is
what was fixed.
2.4.7: an alert's line can be dragged. Nothing an indicator declares
changed. A price or study-threshold alert line is draggable by the trader, and
a study threshold drags on its own plot's scale rather than the instrument's,
including an independent or left scale. Worth knowing for a descriptor whose
plot owns a scale: the preview does not enlarge autoscale and never shows
study units on the price axis. The on-chart badge for an armed alert reads
"Alert"; the serialized lifecycle values are unchanged, so anything reading
alert.state is unaffected.
2.4.6: source access, marker anchoring and a legend that reads. Three
optional descriptor fields, all of which an existing indicator can ignore.
hasSource: true puts a braces button on the legend row beside the gear and
emits indicatorSource with { instanceId, indicatorId, paneIndex }; the
host owns the code and decides what the button opens, so set it only for a
descriptor whose source a host can actually show. markerAnchor: 'price'
measures a marker's aboveBar and belowBar against the instrument's
candles rather than the descriptor's own first plot, which is what a buy or
sell signal on an overlay means: below is below the low. The default stays
'plot', so a mark that belongs to a line keeps sitting on the line, and the
field is ignored on a study that owns a pane. Legend readings now skip a plot
drawn in a fully transparent colour, which matters if you declare an
invisible column to anchor markers or fills to: it no longer reserves the
width of a price in the row. Legend glyphs also scale with their button
rather than the row's text, and ChartOptions.legendIconSize sets that
button across the chart.
2.4.5: optional open interest and host contracts. The published build has
105 built-ins, including open-interest, open-interest-change and
open-interest-buildup. Bar.oi is an optional reading: preserve zero, keep
missing readings as gaps, and never sum OI when folding bars. securitySeries
exposes a nullable oi column. Capability comes from host instrument metadata,
not from whether one bar has a reading. See reference/api.md for an example.
Host trader alerts can target a study's stable instance id and plot key; keep
those plot keys stable and distinguish these alerts from descriptor alerts.
The host owns delivery and pauses trader evaluation during loading and replay.
Instrument, ReplayGroup, exportChartDataCsv and trading capability helpers
are host APIs, not a reason for a study to mutate the chart, control replay or
submit orders. Workspace/template APIs live in openalgo-charts/workspace,
outside the core-plus-indicators object handed to a custom module. Existing
descriptor fields remain compatible. Calculate from the supplied bars so a
replayed study cannot reveal later history.
2.4.0: the constructs a ported study most often could not express. Every
item is optional and needs openalgo-charts 2.4.0 or later installed; the
validator checks against the installed build, so read
node -p "require('./frontend/node_modules/openalgo-charts/package.json').version"
before using any of them, and do not use them on an older pin.
securitySeries(bars, interval, opts) folds the chart's bars to a higher
timeframe, one value per bar, with the three readings named (as it stood at
that bar, the default; offset: k for the last completed bucket;
lookahead: true for final values, which repaints) and
session: '0915-1530' to anchor sub-day buckets to the session open. It
replaces every hand-rolled fold. plot.offset paints a column that many
bars ahead, the tail landing in the right margin, with fills and the legend
following. A calc that throws once installed is reported on the study's
data status instead of thrown into the render loop; throw
IndicatorInputError for a condition the user can fix.
alerts[].message may be a function of the firing bar. Marker shapes
cross and xcross, positions paneTop and paneBottom, pinned to the
plot's edges. fills[].overlay for a band drawn on the price pane.
plot.colorParts for a wick and border coloured apart from the body.
tooltip and id on draws() labels and boxes. Inputs interval and
time. table options fontSize: 'auto'. And
ctx.requestBars on the attach context for another instrument's bars,
which /trading serves from the terminal's own cached feed: the same broker
session and the same bar cache the chart uses, so a benchmark costs no
second transport and no credential reaches a chart setting. Omit exchange
to mean the chart's own. It rejects on a host that registers no provider,
and a study should publish that as unsupported rather than invent a value.
2.3.0: charts can be arithmetic over several instruments.
openalgo-charts/transform gains parseExpression and evaluateExpression,
so /trading can chart NIFTY/RELIANCE, 2*CE25000 - CE25200 or any
expression over any number of legs. These belong to the transform tier,
not to the API object a custom indicator module receives, so nothing about
writing an indicator changes. Worth knowing for one reason: a study added to
a computed chart runs on the folded series, whose bars have no volume and
whose high and low are a bound rather than a measurement unless the host
asked for close-only. Volume studies read zero there, which is honest rather
than broken.
2.2.1: inputs can carry help text, and a plot can label its own axis.
Every IndicatorInput variant now takes an optional tooltip, which the
settings dialog renders as a small focusable ? beside the label. Put the
explanation there rather than in a parenthetical that stretches the row.
IndicatorPlot now takes an optional priceFormat, the same PriceFormat
union addSeries uses, with a new percent variant: it suffixes the value
and does not scale it, so a study returning 0..1 reads 0.62% and one
returning 0..100 reads 62.24%. Multiplying inside calc to make the axis
read better would change the legend, the crosshair and everything computed off
the value. Like style.precision it belongs to a plot that owns its pane.
Both fields are optional, so an existing descriptor is unaffected.
2.2.0: hosts can offer 85 drawing tools. The draw tier adds channels,
pitchforks, Fibonacci and Gann geometry, wavefronts and manual patterns.
ADVANCED_LINE_TOOLS, ADVANCED_GEOMETRY_TOOLS and PATTERN_DRAWING_TOOLS
belong to openalgo-charts/draw; they are not part of the custom indicator's
API object. The indicator descriptor contract and its 102 built-ins are
unchanged. Drawing documents retain version 2 and existing tool IDs.
2.1.9: chart hosts gain built-in branding and
an optional text watermark. ChartOptions.branding defaults to the
OpenAlgo mark, while ChartOptions.watermark defaults off. Hosts can update
them with setBranding and setWatermarkOptions, inspect them with
brandingOptions and watermarkOptions, and follow branding changes through
branding:changed. Blank watermark text follows the symbol and interval from
setDataContext. The public types are LogoWatermarkOptions,
ChartWatermarkOptions, and BrandingChangedEvent. These are host APIs and
do not change or belong inside an indicator descriptor.
2.1.8: navigation can ease automatic price ranges as it reveals new
extrema. animAutoscale follows animZoom by default, while a manual scale
and a descriptor's fixed range() remain authoritative. Normalized wheel and
trackpad gestures and the packaged widget's responsive controls are host
features; they do not change a descriptor. OpenAlgo /trading constructs a
bare Chart, so it receives the engine gestures but keeps its own toolbar,
rails and panels rather than receiving WidgetOptions.mobile controls.
2.1.7: hidden indicators remain hidden through layout restoration and style
edits. Reference levels now follow the instance's visibility along with its
plots and other visuals. The new ChartObjects inventory also exposes an
indicator's visibility and Tier-2 data status to host and widget object
panels, but it does not change the descriptor contract or add work to a
custom indicator.
2.1.6: Tier-2 studies follow the chart's data context and loaded source
range. createTier2Indicator receives dataContext with the host's symbol,
exchange and interval, cancels obsolete fetches, extends history when older
bars arrive and refreshes when the host changes instrument. A descriptor can
use supports(ctx) to report that its provider cannot serve a context. The
managed lifecycle publishes loading, ready, empty, unsupported and error
states with an explicit retry action, so provider failure is visible without
putting network state into calc. Existing Tier-2 descriptors get the range,
cancellation and status behavior through the wrapper without changing shape.
2.1.2: a Tier-2 study's data requests are keyed by data setting. Changing
the symbol or any other data input clears the previous values immediately, and
a response that arrives for the setting you just left cannot land on the new
one. A style-only change reuses the history already in flight instead of
refetching, and a live observation wins over a historical point for the same
time. An attach that used to guard against its own stale responses no longer
has to.
1.8.9: precision is keyed on the pane, not the descriptor. An onchart
plot prints at the instrument's tick; a plot on its own pane prints at that
pane's span with a floor of two decimals. A study pane is no longer formatted
in the instrument's tick, which is why an RSI reads 70.00 rather than 70.0.
Custom descriptors get this with nothing to declare, and a precision input is
still the wrong answer. See Do not, below.
1.8.4: calc runs once per animation frame, not once per tick. A data
update marks the indicators stale and the flush happens before the paint, so a
burst of ticks collapses into one call. calc must therefore be a pure
function of (bars, settings). It always had to be, but running per tick used
to hide an indicator that counted its own calls or accumulated into store.
Reading chart.indicators() or an instance's values() flushes first, so a
read-after-update in the same turn still sees fresh numbers.
1.8.4: calcTail is rarely worth it now. The tick-rate problem it existed
to solve is gone. It only pays when one pass over the loaded history is itself
slow, which means deep history, not a fast feed.
1.8.3: the catalogue went from 91 to 102 built-ins, so a file written
earlier can shadow an id that did not exist when it was named. The new ids are
listed in reference/pitfalls.md under the collision entry. That release also
corrected nine built-ins and moved ten defaults, so an indicator that compares
itself against a built-in may need its expectations re-derived rather than
assumed unchanged.
reference/cookbook.md. Every
author-facing call is demonstrated there, and the first section is the one
that saves the most work: the 112 built-ins are descriptors, so
getIndicator('macd').calc(bars, settings, {}) gives you MACD's own columns
rather than a reimplementation that can drift from the chart's.reference/contract.md for the descriptor
shape and the runtime's exact behaviour, reference/api.md for what is
available inside the module, reference/pitfalls.md for the traps. Read
reference/pitfalls.md before writing anything; most first drafts fail on
something in it.examples/ and work from it:simple_zscore.js — one pane, one plot, rolling window, levels, rangeema_cross_signals.js (2.5.4) — crossesAbove, crossesBelow,
crosses, rising and falling turning two averages into filtered
Buy and Sell markersintermediate_keltner_squeeze.js — several plots, fills, colorBy, a
second price scale, a boolean that hides part of the drawingshaded_trend_zone.js — shading between two series, where the ribbon
flips sides and recolours with the trendcomplex_session_vwap.js — per-session state, markers with a signal
latch, table, calcTail, zone-aware day boundariesregime_shading.js — background(), barColors(), declared alerts
and a data-derived levels(ctx)zones_with_draws.js — draws() with all four kinds, driven by
pivotHigh / pivotLow. The pattern behind structure studiesheikin_ashi_candles.js — a plot fed by four columns via ohlcsession_range_modern.js — parseSessionSpec, inSessionAt and the calc
context, replacing a hand-rolled session parsertier2_external_data.js — createTier2Indicator and the manual attach
lifecycle, for data the chart does not havehigher_timeframe_bands.js (2.4.0) — securitySeries with two of its
three readings, a study in its own pane whose bands and fill carry
overlay: true onto the candles, an interval input, a marker pinned to
the pane edge, an alert message built from the firing bar, and
IndicatorInputError for an input the user can fixdisplaced_cloud_zones.js (2.4.0) — plot.offset for a cloud painted
ahead of its data, colorParts for a wick coloured apart from its body, a
draws() zone with a hover tooltip, a time input, and a table that
sizes its own type. Read it for the difference between a plot, which
cannot leave the bars, and a drawing, which never was on them/trading.
No page reload is needed: the catalogue re-reads the folder every time the
picker opens, and an edited file is re-imported because the URL carries the
file's modification time. A reload is only needed for a chart that was
already open before the app itself changed.Work through the source in this order. Each row is a mechanical translation; the judgement is in the last two.
| In the source | Here |
|---|---|
overlay=true / false | placement: 'onchart' / 'pane' |
every input.* | one inputs[] entry, matching type |
every plot() | a plot key plus that column from calc |
plotshape / plotchar / plotarrow | markers() |
hline | levels(ctx) |
fill() | fills, or background() if it shades the whole pane |
bgcolor() | background() |
barcolor() | barColors() |
plotcandle / plotbar | a plot with ohlc: { open, high, low, close } |
line.new / box.new / label.new / polyline.new | draws() |
alertcondition() | an alerts[] entry |
var state across bars | a variable outside the calc loop |
x[1], x[n] | arr[i - 1], arr[i - n] |
na | null, and guard every comparison |
barstate.* | ctx.barState on the 4th calc argument |
| session strings | parseSessionSpec + inSessionAt |
ta.* | the exported helper of the same job, see reference/api.md |
request.security(syminfo.tickerid, tf, ...) | securitySeries(bars, tf, opts) (2.4.0), see below |
plot(x, offset = n) | plot.offset: n (2.4.0) |
input.timeframe / input.time | type: 'interval' / type: 'time' (2.4.0) |
runtime.error(msg) | throw new IndicatorInputError(msg) (2.4.0) |
alert(dynamic message) | alerts[].message as a function of the bar (2.4.0) |
plotshape(location.top / location.bottom) | position: 'paneTop' / 'paneBottom' (2.4.0) |
shape.cross / shape.xcross | shape: 'cross' / 'xcross' (2.4.0) |
plotcandle(wickcolor = ...) | plot.colorParts returning { body, wick, border } (2.4.0) |
label.new(..., tooltip = ...) | tooltip on a draws() label or box (2.4.0) |
table.new(..., text_size = size.auto) | table options fontSize: 'auto' (2.4.0) |
indicator(precision = n) | style.precision: n on the plot that owns the pane, never an input |
Then the two that need thought:
A higher-timeframe request on the chart's own symbol. From 2.4.0 this is
securitySeries(bars, interval, opts): one fold, three readings. The default
reads the bucket as it stood at that bar and never uses a later one, which is
what the live bar sees and what a non-repainting port wants. offset: 1 is
the last completed bucket, the close[1] pattern. lookahead: true is the
source's lookahead_on: it reads final values on every bar of the bucket and
repaints, so use it only to reproduce a source that did. Pass
session: '0915-1530' so a 30-minute bucket on a 09:15 open runs 09:15 to
09:45 rather than 09:00 to 09:30. On an older pin, fold by hand with
bucketStartOf / zonedDayIndex, and say which reading you chose.
A request against another symbol. A screener over a pasted list of tickers
is not a chart study and cannot be expressed: calc is flushed every frame,
and forty requests belong to a scanner page. A single benchmark (a ratio, a
beta, a spread) can be, from 2.4.0, through ctx.requestBars on the attach
context or a Tier-2 descriptor's series and calc. /trading registers the
provider, so this works here today; fetch in attach, stash in store, call
requestRecompute(), and read it in calc. On a host that registers none the
request rejects, which the study should publish as unsupported.
Anything drawn at a future bar. Two cases, and they differ. A draws()
line, box or label anchored at a time past the last bar renders: the time
scale extrapolates at the last bar spacing, so a right-margin tag, a projected
zone or a bar_index + 3 label works today. A plot column cannot reach
past the last bar, because a column is one value per bar; from 2.4.0
plot.offset: n paints it n bars ahead instead, which is what a displaced
cloud or plot(x, offset = n) means. On an older pin, shift the meaning back
onto existing bars, or drop it and record the gap.
validate.mjs is a pre-flight check, and it is the one that can refuse to
install. The chart validates again at load time, in the browser, where the
library already is: it checks the descriptor before it reaches the catalogue,
and wraps calc so its first result is measured against the bars. Anything
wrong surfaces as a toast naming the file.
That second layer is why a trader with no Node.js at all still gets told what is wrong instead of an indicator that quietly draws nothing.
Plain JavaScript. Nothing compiles it: no TypeScript, no JSX, no imports. The module default-exports one function and is handed the whole charting API.
export default function ({ registerIndicator, sourceValues, sma, nulls }) {
registerIndicator({
id: 'my-thing', // unique slug; prefix your own to avoid overriding a built-in
name: 'My Thing', // picker and legend
category: 'Custom', // groups it in the picker rail
placement: 'onchart', // 'onchart' overlays price, 'pane' gets its own pane
inputs: [ ... ], // becomes the settings dialog
plots: [ ... ], // each key must appear in what calc returns
calc(bars, settings, store) {
return { /* one array per plot key, exactly bars.length long */ }
},
})
}A bar is { time, open, high, low, close, volume } with time in UTC
seconds.
The descriptor is much wider than the plot-plus-calc it started as. Before hand-rolling anything, check whether one of these already covers it:
| Want | Use |
|---|---|
| A trendline, zone, box or free label | draws(ctx) |
| Shade the pane by state | background(ctx) |
| Repaint the price candles | barColors(ctx) |
| A horizontal level from the data | levels(ctx), which receives bars and values |
| A condition the chart watches | alerts[] with a when(ctx) predicate |
| One plot on price from a pane study | plot.overlay: true |
| Candles or bars as a plot | plot.ohlc: { open, high, low, close } |
| Know the bar state, symbol, interval, clock | the 4th calc argument |
| The instrument's tick size | ctx.tickSize, never an input for it |
| The decimals your plots print at | Nothing: it follows the pane, see below |
| Parse a session window | parseSessionSpec, inSessionAt, sessionFlags |
| Reason about the timeframe | intervalParts, isIntradayInterval, ... |
| A colour ramp or alpha | fromGradient, withAlpha |
| Pivots, rank, correlation, linreg | pivotHigh, pivotLow, percentRank, correlation, linreg, ... |
| A higher timeframe of the chart's own bars | securitySeries(bars, interval, opts) (2.4.0), never a hand-rolled fold |
| A plot painted N bars ahead | plot.offset (2.4.0) |
| Another instrument's bars | ctx.requestBars on the attach context (2.4.0), once the host registers a provider |
| A table positioned, sized or coloured per cell | table() options (position, cellWidth, widthPercent, fontSize) and TableCell bgColor / textColor |
| A dotted reference line | levels() entries take lineStyle: 'dotted' |
| Any built-in's maths | getIndicator(id).calc(bars, settings, {}), never a reimplementation |
Full list in reference/api.md, which is generated from the installed build.
Full list in reference/pitfalls.md. These four account for most failures:
bars.length. Short arrays do
not error, they just stop drawing partway.null (or nulls(...) on a helper's NaN output). A 0 puts
a spike at the bottom of the pane and wrecks autoscale.na semantics. Script languages with a not-available value treat every
comparison against it as false. In
JavaScript 5 > null is true. Guard with x != null or signals fire
through the warmup gap.aboveBar / belowBar anchor to this indicator's own
plot line, not to the candle. To place a label relative to a bar, use
position: 'atPrice' with an explicit price.style. Your own width input becomes a second control that
disagrees. That rule is about plots only: a colour that markers(),
draws() or background() reads has no generated control, so a
type: 'color' input for it is right (the source's input.color for a
marker maps to exactly that), and a fills band takes its colours through
colorUpKey / colorDownKey.onchart plot is a price
and prints at the instrument's tick (Supertrend on a 0.05 tick reads
1339.70); a plot on its own pane prints at that pane's own span with a floor
of two decimals (an RSI reads 70.00, a percentage study 0.61). A study pane
is not quoted in the instrument's tick, because an RSI is a dimensionless
0..100 band. If a plot of yours really is a price, put it on the candles with
overlay: true rather than reaching for a precision knob. A source's
indicator(precision = n) is a declared style.precision: n on the plot
that owns the pane, which is a style the chart honours, not an input the
user can turn.ctx.tickSize carries it, and an
input is a second source of truth that disagrees with the axis. Point value is
the exception: the chart does not know it, so that one is an input at 1.zonedDayIndex /
utcSecondsToZonedParts with a zone, defaulting to DEFAULT_TIMEZONE.| Path | |
|---|---|
strategies/indicators/*.js | installed indicators, gitignored, never pushed |
.claude/skills/chart-indicator/validate.mjs | the gate |
.claude/skills/chart-indicator/examples/ | twelve validated worked examples |
.claude/skills/chart-indicator/reference/ | contract, API surface, pitfalls, cookbook |
.claude/skills/chart-indicator/coverage.mjs | fails if an API or capability is documented but never demonstrated |
.claude/skills/chart-indicator/generate-api-index.mjs | regenerates the export index in reference/api.md; --check fails when it is stale |
docs/custom-indicators.md | the user-facing guide |
blueprints/custom_indicators.py | serves the folder to the chart |
frontend/src/lib/trading/customIndicators.ts | the loader |
Indicators are loaded over HTTP at runtime, not bundled, so they survive
git pull and need no rebuild. They run with full access to the logged-in
session: treat an indicator file from an untrusted source as you would any
script you are about to run.
© marketcalls, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 21 other files in .claude/skills/chart-indicator of marketcalls/openalgo.
Open the folder on GitHubat commit 6a6f201
Chart Indicator next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Chart Indicator this skillmarketcalls/openalgo | 2.8k | — | ~8.7k | Automated safety check: Notes | AGPL-3.0 | |
| Tushare Datazillionare/zillionare | 319 | 2 repos | ~2.3k | Automated safety check: Pass | None | |
| Okx Cex Marketdex-original/okx-agent-trade-kit | 109 | 1 repos | ~2.7k | Automated safety check: Pass | MIT | |
| Kalshi Traderyanfrigo/kalshi-ai-trading-bot | 612 | — | ~3.4k | Automated safety check: Pass | MIT | |
| Polymarket Tennislivetennisapi/livetennisapi-mcp | 152 | — | ~3k | Automated safety check: Pass | MIT | |
| Okx Cex Smartmoneydex-original/okx-agent-trade-kit | 109 | 1 repos | ~1.4k | Automated safety check: Pass | MIT |
zillionare/zillionare
面向中文自然语言的 Tushare 数据研究技能。用于把“看看这只股票最近怎么样”“帮我查财报趋势”“最近哪个板块最强”“北向资金在买什么”“给我导出一份行情数据”这类请求,转成可执行的数据获取、清洗、对比、筛选、导出与简要分析流程。适用于 A 股、指数、ETF/基金、财务、估值、资金流、公告新闻、板块概念与宏观数据等研究场景。
dex-original/okx-agent-trade-kit
A skill your agent uses when the user asks for: price of any asset, ticker, order book, candles, OHLCV, funding rate, open interest, OI change scanner, market screener (top movers, high-volume…
ryanfrigo/kalshi-ai-trading-bot
The disciplined process for autonomously and profitably trading the live Kalshi account on each /loop tick, with Claude as the decision-maker.
livetennisapi/livetennisapi-mcp
Build observe-only Polymarket and Kalshi tennis market tooling on the polymarket-tennis Python package (MIT) plus the Live Tennis API free tier.
dex-original/okx-agent-trade-kit
Smart Money analytics on OKX: leaderboard traders, position tracking, trade records, aggregated consensus signals, and signal history.
joemccann/market-data-warehouse
Institutional-grade Python backtesting framework builder for Codex.
marketcalls/openalgo
Integrate a new Indian broker into OpenAlgo, or modify an existing broker plugin.
marketcalls/openalgo
Audit a change for resource leaks in OpenAlgo — file descriptors AND unbounded memory growth.
marketcalls/openalgo
Build, edit or debug an OpenAlgo Flow workflow - the no-code node graph at /flow.
marketcalls/openalgo
Write an OpenScript study or strategy for OpenAlgo, and install it into strategies/openscript/ only after it compiles.
marketcalls/openalgo
Run OpenAlgo's periodic security audit across backend, frontend, database, cache, routes and dependencies, producing a dated xlsx report.
marketcalls/openalgo
Verify a claim before stating it, and verify a test before trusting it.
Categories
Build a custom indicator for the OpenAlgo /trading charting terminal (openalgo-charts). Chart Indicator is an agent skill from marketcalls/openalgo. Build a custom indicator for the OpenAlgo /trading charting terminal (openalgo-charts).
Chart Indicator fits situations like: asked to create; debug a chart indicator; on-chart signal; including porting a study written for another charting platform.
Run `npx skills add marketcalls/openalgo --skill chart-indicator -a claude-code`. Or copy the skill folder (.claude/skills/chart-indicator in marketcalls/openalgo) into .claude/skills/chart-indicator in your project. Claude Code loads it when a task matches its description.
Run `npx skills add marketcalls/openalgo --skill chart-indicator -a codex`. Or copy the skill folder (.claude/skills/chart-indicator in marketcalls/openalgo) into .agents/skills/chart-indicator in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add marketcalls/openalgo --skill chart-indicator -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/chart-indicator, .gemini/skills/chart-indicator, .github/skills/chart-indicator and .opencode/skills/chart-indicator in your project.
Going by SKILL.md and its folder, Chart Indicator needs JavaScript for the scripts in its folder and the command-line tools its instructions call (node, npm and git). Our summary lists: Python 3; Node.js. Its frontmatter pre-approves these tools: Read, Write, Edit, Bash, Glob, Grep.
SKILL.md contains no URLs. Its commands use npm and git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found notes only (pre-approves every shell command (allowed-tools: bash)), nothing it rates as a warning. It is not a guarantee. Review the folder before installing.
Chart Indicator is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 8.7k tokens (SKILL.md is roughly 35k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Chart Indicator: Tushare Data (zillionare/zillionare, 319 stars), Okx Cex Market (dex-original/okx-agent-trade-kit, 109 stars), Kalshi Trade (ryanfrigo/kalshi-ai-trading-bot, 612 stars) and Polymarket Tennis (livetennisapi/livetennisapi-mcp, 152 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
marketcalls (a GitHub user) maintains it in marketcalls/openalgo, which has 2,797 GitHub stars. The repository holds 8 skills in this directory. The repository was last updated on October 8, 2026.
Source: marketcalls/openalgo on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.