From mph-kit
Builds TradingView Pine Script v6 indicators in a consistent house style with synthwave dashboard aesthetics, faithful math, and v6 compliance. Handles porting from Python or other Pine scripts.
How this skill is triggered — by the user, by Claude, or both
Slash command
/mph-kit:mph-pineThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build TradingView Pine Script v6 indicators that look and behave like the mphinance house stable (channels.pine, ghost_dashboard.pine, ghost_alpha.pine). Faithful math, clean v6, a synthwave dashboard, and a compressed AI-readable payload row so Gemini or Sam can read the chart.
Build TradingView Pine Script v6 indicators that look and behave like the mphinance house stable (channels.pine, ghost_dashboard.pine, ghost_alpha.pine). Faithful math, clean v6, a synthwave dashboard, and a compressed AI-readable payload row so Gemini or Sam can read the chart.
Use when the user asks to build, port, or extend a TradingView indicator or strategy: "write a pine indicator", "tradingview indicator for X", "port this Python signal to Pine", "add alerts to my script", "/mph-pine". If the user names an existing engine (a Python scanner, a screener rule), treat that as the source of truth and port it faithfully before adding extras.
//@version=6.docs/pine/<name>.pine in the relevant repo. Offer /ship. Never commit without being asked.These are the v6 breaking changes and gotchas that bite when porting from v5 or from memory:
bool cannot be na. Never write var bool x = na. Use an int flag (0 / 1 / -1) for tri-state. na(), nz(), fixnan() no longer accept bool.if count > 0, not if count.and / or are lazy. Short-circuit is fine, but do not rely on side effects in the right operand.input.enum. Declare enum Name with optional field = "Title" strings, then input.enum(Name.first, "Label"). Compare with ==. Cleaner than magic strings.request.security. A single call can take a series string symbol or timeframe. Use lookahead=barmerge.lookahead_off to stay non-repainting.input.timeframe("") off-slot trick. An empty timeframe means the chart timeframe. For an optional higher-TF confirm, never gate request.security behind a ternary on the empty string (Pine evaluates both branches). Instead call request.security on a fallback (htf_on ? htf_tf : timeframe.period) and ignore the result when off.plotchar / plotshape args must be const. char, text, and location cannot be series. Split a direction-dependent marker into two calls with fixed location.belowbar / location.abovebar.f_*() at top level, never inside an if block or a local scope.ta.median. Use ta.percentile_linear_interpolation(src, len, 50).max_bars_back, max_lines_count, max_labels_count on indicator() when drawing persistent objects or looping over history.// <Name> [mph1nance] - <one line purpose>
// (c) mph1nance + Sam the Quant Ghost
//
// PURPOSE: <what it does and why it beats the generic version>
// Faithful port of <source>. Constants: <list them>.
//@version=6
indicator("<Name> [mph1nance]", "<glyph>", overlay=true, max_bars_back=600, max_lines_count=30, max_labels_count=50)
// Synthwave palette (reuse these names)
const color C_BULL = #00FFFF
const color C_BEAR = #FF00FF
const color C_NEUTRAL = #9C27B0
const color C_BREAK = #FF3D00
const color C_CONF = #00FFCC
const color C_WARN = #FFD740
const color C_BG = #090014
const color C_BORDER = #FF00FF
const color C_TEXT = #00FFFF
// Grouped inputs
g_main = "--- Main ---"
// ... input.int / input.float / input.enum, all with group=g_main
Build the table once on barstate.isfirst, fill it on barstate.islast. Left column is the label, right column is the value, color carries meaning. End with a single compressed pipe-delimited row that an OCR or screenshot reader can parse.
var table tbl = na
if barstate.isfirst and show_tbl
tbl := table.new(tbl_pos, 2, 16, bgcolor=C_BG, border_width=2, border_color=C_BORDER, frame_width=3, frame_color=C_BORDER)
if barstate.islast and show_tbl
int row = 0
table.cell(tbl, 0, row, "<TITLE>", text_color=C_TEXT, text_halign=text.align_center, bgcolor=color.new(C_BORDER, 70))
table.merge_cells(tbl, 0, row, 1, row)
row += 1
// ... one row per metric, color-coded ...
// Final AI payload row, merged across both columns:
string ai = syminfo.ticker + "|" + timeframe.period + "|" + verdict + "|" + str.tostring(value)
table.cell(tbl, 0, row, ai, text_color=color.new(C_TEXT, 75), text_size=size.tiny, text_halign=text.align_center)
table.merge_cells(tbl, 0, row, 1, row)
Pair static alertcondition calls (one per discrete event) with a single dynamic alert() on bar close that carries the full context string.
alertcondition(brk_above, "Breakout up", "Price broke above")
if barstate.isconfirmed and (brk_above or brk_below)
alert(syminfo.ticker + " " + timeframe.period + " | " + verdict + " | " + str.tostring(score), alert.freq_once_per_bar_close)
Array index convention: a = 0 is the oldest bar in the window, a = len-1 is the latest. The series offset for index a is src[(len-1)-a].
f_linreg(float src, int len) =>
float n = len, sx = 0.0, sy = 0.0, sxx = 0.0, sxy = 0.0, syy = 0.0
for i = 0 to len - 1
float xi = i, yi = src[(len - 1) - i]
sx += xi
sy += yi
sxx += xi * xi
sxy += xi * yi
syy += yi * yi
float denx = n * sxx - sx * sx
float deny = n * syy - sy * sy
float slope = denx == 0.0 ? 0.0 : (n * sxy - sx * sy) / denx
float icept = (sy - slope * sx) / n
float r2 = (denx == 0.0 or deny == 0.0) ? 0.0 : math.max(0.0, math.min(1.0, math.pow(n * sxy - sx * sy, 2) / (denx * deny)))
[slope, icept, r2]
Note: declare each local on its own line in real code. Pine does not accept comma-separated declarations on one line. The above is compressed for the doc only.
Loop the window, accumulate (yi - (slope*i + icept))^2, return sqrt(sum / len). Matches numpy np.std.
float vol_med = ta.percentile_linear_interpolation(volume, 20, 50)
bool vol_strong = vol_med > 0.0 and volume > 1.5 * vol_med // VOLUME_CONFIRM_MULT
Stop a buffer (for example 0.5 ATR) beyond the relevant level. In-channel setups target the opposite rail; breakout setups target a measured move (one channel height). Always guard risk > 0 before dividing.
Detect the raw pattern, then only flag it when it prints AT a level. A hammer in open space is noise. A hammer tagging the lower rail of an ascending channel is a signal.
float body = math.abs(close - open), rng = high - low
float up = high - math.max(close, open), dn = math.min(close, open) - low
bool doji = rng > 0.0 and body <= rng * 0.1
bool hammer = rng > 0.0 and dn >= body * 2.0 and up <= body and not doji
bool bull_eng = close > open and close[1] < open[1] and close >= open[1] and open <= close[1]
bool react_bull = tag_lower and (hammer or bull_eng) // tag_lower = price reached the level
docs/pine/<name>.pine. Surface the absolute path. Offer /ship, never auto-commit.npx claudepluginhub mphinance/alpha-skills --plugin mph-kitPine Script v5/v6 indicator scaffold and patterns. Provides structure guidance and triggers doc-researcher for current syntax verification. Use when developing TradingView indicators.
Standardized template for defining trading strategies with entry rules, exit rules, position sizing, risk parameters, and performance criteria.
Generates BUY/SELL trading signals with confidence scores using RSI, MACD, Bollinger Bands and more for crypto/stocks watchlists. Scans, ranks opportunities, adds stop-loss/take-profit.