(window.webpackJsonp=window.webpackJsonp||[]).push([[121],{vmXC:function(e,t,n){"use strict";n.r(t),n.d(t,"_frontmatter",(function(){return p})),n.d(t,"default",(function(){return m}));var a=n("Fcif"),l=n("dV/x"),b=(n("mXGw"),n("/FXl")),r=n("TjRS"),i=n("wCAC");n("l1C2");const c=["components"],p={};void 0!==p&&p&&p===Object(p)&&Object.isExtensible(p)&&!Object.prototype.hasOwnProperty.call(p,"__filemeta")&&Object.defineProperty(p,"__filemeta",{configurable:!0,value:{name:"_frontmatter",filename:"src/components/zh/Scripting.mdx"}});const o={_frontmatter:p},d=r.a;function m(e){let{components:t}=e,n=Object(l.a)(e,c);return Object(b.b)(d,Object(a.a)({},o,n,{components:t,mdxType:"MDXLayout"}),Object(b.b)("h1",{id:"自定义指标-api"},"自定义指标 API"),Object(b.b)(i.e,{mdxType:"Lead"},"用 JavaScript 编写自己的指标,在图表旁的安全沙箱中运行,并与其他用户分享。API 提供市场数据(K线、订单簿、集群、强平、衍生品数据)、绘图原语、技术分析函数和提醒。"),Object(b.b)("h2",{id:"使用-ai-生成指标"},"使用 AI 生成指标"),Object(b.b)("p",null,"完整的 API 也以单个文本文件的形式提供给语言模型使用:",Object(b.b)("a",{parentName:"p",href:"../../public/AI-scripting.txt"},"AI-scripting.txt"),"。将其附加到 ChatGPT、Claude、Gemini 或其他任意 LLM,并描述你想要的指标。"),Object(b.b)("p",null,"示例提示词:"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-text"},"Read the attached [AI-scripting.txt] https://mobchart.com/docs/public/AI-scripting.txt file and use it as the only reference for the MobChart scripting API.\n\nCreate a custom indicator that plots a 20-period EMA and a 50-period EMA on the chart. Color the candles green when EMA20 is above EMA50 and red otherwise.\n\nUse only the documented API. Do not invent functions. Return the complete indicator code.\n")),Object(b.b)("h2",{id:"沙箱与限制"},"沙箱与限制"),Object(b.b)(i.b,{type:"warning",title:"当前限制",mdxType:"Callout"},Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"脚本在安全的 JavaScript 沙箱中运行。"),Object(b.b)("li",{parentName:"ul"},"脚本的执行时间上限为 ",Object(b.b)("inlineCode",{parentName:"li"},"1500ms"),"。"),Object(b.b)("li",{parentName:"ul"},"返回的数据数组最多 ",Object(b.b)("strong",{parentName:"li"},"5000")," 个元素,因此指标最多只能回溯 ",Object(b.b)("strong",{parentName:"li"},"5000 根K线"),"。"),Object(b.b)("li",{parentName:"ul"},"单个指标内最多允许 ",Object(b.b)("strong",{parentName:"li"},"8 次数据源请求"),"。"),Object(b.b)("li",{parentName:"ul"},"单次运行内最多允许 ",Object(b.b)("strong",{parentName:"li"},"3 次 HTTP 请求"),"(",Object(b.b)("inlineCode",{parentName:"li"},"http.get")," / ",Object(b.b)("inlineCode",{parentName:"li"},"http.post"),"),参见 ",Object(b.b)("strong",{parentName:"li"},"HTTP 请求"),"。"))),Object(b.b)("h2",{id:"指标开发"},"指标开发"),Object(b.b)("p",null,"指标在一个单独的组件中开发,该组件可以放在启用该指标的图表旁边。"),Object(b.b)(i.f,{src:"../../public/chart_code.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"创建指标"},"创建指标"),Object(b.b)("h3",{id:"definetitle-description-type-ispublic-ispubliccode-options"},Object(b.b)("inlineCode",{parentName:"h3"},"define(title, description, type, isPublic, isPublicCode, options)")),Object(b.b)("p",null,"在系统中注册指标。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"参数"),Object(b.b)("th",{parentName:"tr",align:null},"类型"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"title")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"指标名称")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"description")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"简短描述")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"type")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"'onchart'")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"'offchart'")),Object(b.b)("td",{parentName:"tr",align:null},"指标位置(图表上或单独面板中)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"isPublic")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"指标是否公开")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"isPublicCode")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"源代码是否公开")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"options")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"object"),"(可选)"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"{ fullRange, warmup }"),",见下文")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("My Indicator", "Shows EMA line", "onchart", true, false);\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"计算范围。")," 默认情况下,脚本只计算图表中需要计算的部分:向左滚动时加载的K线,或刷新时的最新K线,再加上它们之前 ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"warmup"))," 根历史K线(默认 500),这些K线参与计算但不会返回。当指标需要更多或更少的历史数据时,请声明 ",Object(b.b)("inlineCode",{parentName:"p"},"warmup"),",例如 EMA(200) 使用 ",Object(b.b)("inlineCode",{parentName:"p"},"{ warmup: 200 }"),"。如果脚本的数值或图形依赖于 ",Object(b.b)("strong",{parentName:"p"},"整个可见范围"),"(从第一根可见K线开始的 VWAP、累计 delta、窗口最高点处的标签、横跨整个图表的水平位),则必须声明 ",Object(b.b)("inlineCode",{parentName:"p"},"{ fullRange: true }"),",否则在加载更多历史后结果会出错。每次保存脚本时都会从 ",Object(b.b)("inlineCode",{parentName:"p"},"define()")," 读取该模式:未声明 ",Object(b.b)("inlineCode",{parentName:"p"},"fullRange")," 保存的脚本按部分方式计算,因此编辑现有的累计类脚本时请加上该标志。部分计算的脚本也会分段加载:在较长的历史上启用时,图表会先请求最新的 500 根K线(若 ",Object(b.b)("inlineCode",{parentName:"p"},"warmup")," 更大则请求 ",Object(b.b)("inlineCode",{parentName:"p"},"warmup")," 根),较早的部分随后逐个请求,因此可见部分会立即显示。带 ",Object(b.b)("inlineCode",{parentName:"p"},"fullRange")," 的脚本始终在整个范围上通过单次请求计算。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("Window max", "Label at the highest visible high", "onchart", true, true, { fullRange: true });\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"onchart")," 和 ",Object(b.b)("strong",{parentName:"p"},"offchart")," 的指标位置:"),Object(b.b)(i.f,{src:"../../public/onchart_offchart.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"输入参数"},"输入参数"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"input"))," 和 ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"style"))," 类用于创建用户可配置的设置(类似 PineScript 中的 ",Object(b.b)("inlineCode",{parentName:"p"},"input()"),")。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"数值输入")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"范围输入")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(b.b)("td",{parentName:"tr",align:null},"下拉选择")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"颜色选择器")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"布尔输入")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"主要参数示例(input):")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const length = input.number("Period", 14, 1, 100, 1);\nconst type = input.select("Type", \'sma\', [\'sma\', \'ema\']);\nconst color = input.color("Line Color", "#FF0000");\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"或视觉参数(style):")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const length = style.number("Size", 14, 1, 100, 1);\nconst color = style.select("Background Color", \'#FF0000\', ["#FF0000", "#AA0000", "#BB0000"]);\nconst color = style.color("Background Color", "#FF0000");\n')),Object(b.b)(i.f,{src:"../../public/input_style.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"数据源"},"数据源"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"source"))," 类从服务器获取市场数据。基于K线的方法使用相同的参数;两个实时快照方法不同:",Object(b.b)("inlineCode",{parentName:"p"},"orderbook()")," 接收交易所和交易对,",Object(b.b)("inlineCode",{parentName:"p"},"levels()")," 接收交易所和设置对象。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"参数"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"exchange"),", ",Object(b.b)("inlineCode",{parentName:"td"},"ticker"),", ",Object(b.b)("inlineCode",{parentName:"td"},"timeframe")),Object(b.b)("td",{parentName:"tr",align:null},"默认为打开该指标的图表。传入其他值可获取其他市场的数据。")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"lookback")),Object(b.b)("td",{parentName:"tr",align:null},"从当前日期起的历史K线数量,",Object(b.b)("strong",{parentName:"td"},"不超过 5000"),"。")))),Object(b.b)(i.b,{type:"note",title:"数据与图表K线对齐",mdxType:"Callout"},Object(b.b)("p",null,"图表周期下的 ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()"),"、",Object(b.b)("inlineCode",{parentName:"p"},"depths()"),"、",Object(b.b)("inlineCode",{parentName:"p"},"clusters()"),"、",Object(b.b)("inlineCode",{parentName:"p"},"liquidations()")," 和 ",Object(b.b)("inlineCode",{parentName:"p"},"moreData()")," 返回 ",Object(b.b)("strong",{parentName:"p"},"每根图表K线一条记录"),":",Object(b.b)("inlineCode",{parentName:"p"},"depths()[i]")," 是 ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()[i]")," 的订单簿,",Object(b.b)("inlineCode",{parentName:"p"},"moreData()[i]")," 是其衍生品数据,依此类推。当某个数据源在某根K线上没有记录时(例如订单簿历史比K线历史短),该条目为 ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"null")),",因此务必进行检查。通过 ",Object(b.b)("inlineCode",{parentName:"p"},"lookback")," 或其他周期请求的数据按原样返回,需要按 ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"startTime"))," 进行匹配。图表市场的 ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()")," 只包含服务器已加载的K线,绝不为 ",Object(b.b)("inlineCode",{parentName:"p"},"null"),";在更早的历史仍在加载时,指标会自动重新计算。")),Object(b.b)("h3",{id:"ohlcvexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"ohlcv(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"K线数据。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "open": 115886.17,\n "high": 115911.96,\n "low": 115764.27,\n "close": 115815.16,\n "volume": 228.41528,\n "startTime": 1757699100000\n },\n {...},\n ...\n] \n')),Object(b.b)("h3",{id:"depthsexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"depths(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"历史订单簿快照,每根K线一个。只保存最大的限价单(即热力图背后的数据)。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "asks": {\n "109425": 5.467,\n "109495": 3.564,\n ...\n },\n "bids": {\n "33000": 3.746,\n "35000": 16.49,\n ...\n }\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"clustersexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"clusters(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"集群(足迹图)数据:K线每个价格档位上的买入和卖出成交量。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "totalBuy": 16053385,\n "totalSell": 20490989,\n "0.8654": { "buy": 286845, "sell": 336689 },\n "0.8653": { "buy": 271848, "sell": 259167 },\n "0.8652": { "buy": 318814, "sell": 373497 },\n ...\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"liquidationsexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"liquidations(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"K线每个价格档位上的强平成交量(仅限合约市场)。格式与 ",Object(b.b)("inlineCode",{parentName:"p"},"clusters()")," 相同。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n {\n "data": {\n "totalBuy": 16053385,\n "totalSell": 20490989,\n "0.8654": { "buy": 286845, "sell": 336689 },\n "0.8653": { "buy": 271848, "sell": 259167 },\n "0.8652": { "buy": 318814, "sell": 373497 },\n ...\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"moredataexchange-ticker-timeframe-lookback"},Object(b.b)("inlineCode",{parentName:"h3"},"moreData(exchange, ticker, timeframe, lookback?)")),Object(b.b)("p",null,"每根K线的衍生品数据:资金费率、未平仓合约K线、多空比(仅限合约市场)。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n { \n "data": {\n "FR": 0.00003777, // 资金费率\n "OI": { // 未平仓合约K线\n "open": 85645.708,\n "close": 83496.225,\n "high": 85801.04,\n "low": 83397.918\n },\n "LS": { "l": 0.5426, "s": 0.4574 }, // 多空比\n "taLS": { "l": 0.552, "s": 0.448 }, // 大户账户多空比\n "tpLS": { "l": 0.5996, "s": 0.4004 } // 大户持仓多空比\n },\n "startTime": 1757699100000\n },\n {...},\n ...\n]\n\n')),Object(b.b)("h3",{id:"orderbookexchange-ticker"},Object(b.b)("inlineCode",{parentName:"h3"},"orderbook(exchange, ticker)")),Object(b.b)("p",null,"实时订单簿快照:当前的完整订单簿,不与K线绑定。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n "asks": {\n "109425": 5.467,\n "109495": 3.564,\n ...\n },\n "bids": {\n "109400": 1.2,\n "109390": 0.8,\n ...\n }\n}\n\n')),Object(b.b)("p",null,"价格档位未排序,请使用 ",Object(b.b)("inlineCode",{parentName:"p"},"ta")," 的订单簿辅助函数(",Object(b.b)("inlineCode",{parentName:"p"},"ta.bestBid"),"、",Object(b.b)("inlineCode",{parentName:"p"},"ta.sumBids")," 等)处理订单簿。\nK线的历史订单簿来自 ",Object(b.b)("inlineCode",{parentName:"p"},"depths()"),":",Object(b.b)("inlineCode",{parentName:"p"},"depths()[i].data")," 格式相同,但其中只保存最大的限价单。"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},"const candles = source.ohlcv(); // exchange、ticker 和 timeframe 参数默认为当前图表。\nconst closes = candles.map(c => c.close);\n")),Object(b.b)("h3",{id:"levelsexchange-settings"},Object(b.b)("inlineCode",{parentName:"h3"},"levels(exchange, settings?)")),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"流动性筛选器")," 的价位:某交易所挂着的大额限价单,使用与筛选器页面相同的设置进行过滤。实时数据,不与K线绑定。没有订阅计划时,距离限制为 1%,存续时间限制为 60 分钟,结果限制为 200 个价位;有订阅计划时最多 2000 个价位。最大的订单排在最前。计为一次数据源请求。"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n "BTCUSDT": {\n "asks": {\n "109500": {\n "price": 109500,\n "quantity": 42.5, // 以基础资产计的数量\n "quantityUSDT": 4653750, // 以计价货币计的数量\n "distance": 0.62, // 与当前价格的距离,百分比\n "duration": 184, // 订单已挂单的分钟数\n "touches": 2,\n "currentTouches": 1,\n "filledPercent": 12.4,\n "strength": 95.5, // 百分比,参见筛选器\n "diversity": 11,\n "isContinuous": true,\n "date": "2026-10-10T06:12:03.000Z"\n },\n ...\n },\n "bids": { ... },\n "volume1hTotal": 183000000\n },\n ...\n}\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"设置"),"(均为可选):"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"设置"),Object(b.b)("th",{parentName:"tr",align:null},"默认值"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tickers")),Object(b.b)("td",{parentName:"tr",align:null},"所有交易对"),Object(b.b)("td",{parentName:"tr",align:null},"仅限该交易所的这些交易对")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"exclude")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"[]")),Object(b.b)("td",{parentName:"tr",align:null},"要跳过的交易对")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"type")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"all"')),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"all"'),"、",Object(b.b)("inlineCode",{parentName:"td"},'"bids"')," 或 ",Object(b.b)("inlineCode",{parentName:"td"},'"asks"'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"nearness")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"5")),Object(b.b)("td",{parentName:"tr",align:null},"与当前价格的最大距离,百分比")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"size")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"100000")),Object(b.b)("td",{parentName:"tr",align:null},"以计价货币计的最小订单规模")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"lifespan")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"订单已挂单的最少分钟数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"touches"),", ",Object(b.b)("inlineCode",{parentName:"td"},"currentTouches")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"价位 / 当前订单的最少触及次数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"filled")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"订单已成交部分的最小值,百分比")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strength"),", ",Object(b.b)("inlineCode",{parentName:"td"},"diversity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"最小强度(百分比)和多样性,与筛选器相同")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"continuousOnly")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"跳过消失后又重新出现的订单")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"volume1h")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0")),Object(b.b)("td",{parentName:"tr",align:null},"交易对 1 小时成交量的最小值,以计价货币计")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"spotAndFutures")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"仅限同时存在于现货和合约市场的交易对")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"limit")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"500")),Object(b.b)("td",{parentName:"tr",align:null},"价位的最大数量,最大的在前(最多 2000)")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// 将图表市场价格附近的大单绘制为水平线,并标注数量和存续时间\nconst candles = await source.ohlcv();\nconst lastDate = candles.at(-1).startTime;\nconst levels = await source.levels(currentExchange, { tickers: [currentTicker], nearness: 3, size: 300000, lifespan: 30 });\nconst own = levels[currentTicker] || { asks: {}, bids: {} };\nfor (const [type, color] of [["asks", "#ef5350"], ["bids", "#26a69a"]]) {\n for (const [price, level] of Object.entries(own[type])) {\n plot.horizontalLine(`${type} ${price}`, +price, color, 0.8, Math.min(4, 1 + level.quantityUSDT / 1e6));\n plot.text(`${type} ${price} label`, `${(level.quantityUSDT / 1e6).toFixed(2)}M · ${level.duration}m`, lastDate, +price, 10, color);\n }\n}\n')),Object(b.b)("h2",{id:"http-请求"},"HTTP 请求"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"http"))," 类向外部 HTTP API 发送请求并返回响应,使指标可以使用 ",Object(b.b)("inlineCode",{parentName:"p"},"source")," 中没有的数据:你自己的服务器、公共 REST API、链上指标提供商等。\n与 ",Object(b.b)("inlineCode",{parentName:"p"},"source.*")," 一样,这些调用以同步函数的形式编写,无需 ",Object(b.b)("inlineCode",{parentName:"p"},"await"),"。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"get(url, options?)")),Object(b.b)("td",{parentName:"tr",align:null},"GET 请求")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"post(url, body?, options?)")),Object(b.b)("td",{parentName:"tr",align:null},"POST 请求。对象或数组形式的 ",Object(b.b)("inlineCode",{parentName:"td"},"body")," 以 JSON 发送(",Object(b.b)("inlineCode",{parentName:"td"},"Content-Type: application/json"),"),字符串按原样发送")))),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"options")," 为 ",Object(b.b)("inlineCode",{parentName:"p"},"{ headers: { name: value } }")," — 最多 ",Object(b.b)("strong",{parentName:"p"},"10")," 个自定义请求头(例如 ",Object(b.b)("inlineCode",{parentName:"p"},"Authorization")," 或 ",Object(b.b)("inlineCode",{parentName:"p"},"x-api-key"),")。"),Object(b.b)("p",null,"两个方法返回相同的响应对象,且 ",Object(b.b)("strong",{parentName:"p"},"从不抛出异常"),":"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'{\n ok: true, // 状态码 200–299\n status: 200, // HTTP 状态码,请求未发送时为 0\n headers: { "content-type": "application/json", ... },\n data: { ... }, // 解析为 JSON 的响应体,响应体不是 JSON 时为 null\n text: "...", // 原始响应体\n error: null // 请求失败的原因:"timeout"、"url not allowed"、"too many requests" 等\n}\n')),Object(b.b)(i.b,{type:"warning",title:"限制与安全",mdxType:"Callout"},Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"每次脚本运行最多 ",Object(b.b)("strong",{parentName:"li"},"3 次请求"),",每个用户 ",Object(b.b)("strong",{parentName:"li"},"每分钟 60 次请求"),"。"),Object(b.b)("li",{parentName:"ul"},"仅限公共 ",Object(b.b)("inlineCode",{parentName:"li"},"http://")," / ",Object(b.b)("inlineCode",{parentName:"li"},"https://")," URL。发往 ",Object(b.b)("inlineCode",{parentName:"li"},"localhost"),"、私有网络和云元数据地址的请求会被拒绝,",Object(b.b)("strong",{parentName:"li"},"不跟随")," 重定向(",Object(b.b)("inlineCode",{parentName:"li"},"3xx")," 响应按原样返回)。"),Object(b.b)("li",{parentName:"ul"},"请求从 MobChart 代理服务器发出:目标 API 只能看到代理地址,永远看不到你的 IP。"),Object(b.b)("li",{parentName:"ul"},"超时 ",Object(b.b)("strong",{parentName:"li"},"5 秒"),",请求体最大 ",Object(b.b)("strong",{parentName:"li"},"64 KB"),",响应最大 ",Object(b.b)("strong",{parentName:"li"},"512 KB"),"(更大的响应会以 ",Object(b.b)("inlineCode",{parentName:"li"},"response too large")," 失败)。"),Object(b.b)("li",{parentName:"ul"},"无法设置 ",Object(b.b)("inlineCode",{parentName:"li"},"Host"),"、",Object(b.b)("inlineCode",{parentName:"li"},"Cookie"),"、",Object(b.b)("inlineCode",{parentName:"li"},"Proxy-*"),"、",Object(b.b)("inlineCode",{parentName:"li"},"X-Forwarded-*")," 及其他连接相关请求头,",Object(b.b)("inlineCode",{parentName:"li"},"Set-Cookie")," 永远不会返回。"),Object(b.b)("li",{parentName:"ul"},"提醒检查会定期在服务器上运行你的脚本:每次检查都会调用该 API,请注意目标 API 的频率限制。"),Object(b.b)("li",{parentName:"ul"},"公开指标(",Object(b.b)("inlineCode",{parentName:"li"},"isPublicCode = true"),")的代码对所有人可见 — 切勿在公开代码中放入 API 密钥。"))),Object(b.b)("p",null,"可能的 ",Object(b.b)("inlineCode",{parentName:"p"},"error")," 值:",Object(b.b)("inlineCode",{parentName:"p"},"invalid url"),"、",Object(b.b)("inlineCode",{parentName:"p"},"url not allowed"),"、",Object(b.b)("inlineCode",{parentName:"p"},"invalid headers"),"、",Object(b.b)("inlineCode",{parentName:"p"},"invalid body"),"、",Object(b.b)("inlineCode",{parentName:"p"},"body too large"),"、",Object(b.b)("inlineCode",{parentName:"p"},"response too large"),"、",Object(b.b)("inlineCode",{parentName:"p"},"timeout"),"、",Object(b.b)("inlineCode",{parentName:"p"},"too many requests"),"、",Object(b.b)("inlineCode",{parentName:"p"},"rate limit"),"、",Object(b.b)("inlineCode",{parentName:"p"},"busy"),"、",Object(b.b)("inlineCode",{parentName:"p"},"proxy unavailable"),"、",Object(b.b)("inlineCode",{parentName:"p"},"network error"),"。"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例(GET):")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("Fear & Greed", "Crypto Fear & Greed index", "offchart", true, true);\n\nconst res = http.get("https://api.alternative.me/fng/?limit=30");\nif (!res.ok) logger.log("request failed:", res.status, res.error);\n\n// res.data = { data: [{ value: "71", timestamp: "1757635200" }, ...] }\nconst byDay = {};\n(res.data?.data || []).forEach((row) => { byDay[Number(row.timestamp) * 1000] = Number(row.value); });\n\nconst candles = source.ohlcv();\nconst values = candles.map((c) => c ? byDay[c.startTime - (c.startTime % 86400000)] ?? null : null);\nplot.lineSeries("Fear & Greed", values, "#00C8FF");\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例(POST):")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nconst last = candles.at(-1);\n\nconst res = http.post(\n "https://example.com/api/signals",\n { exchange: currentExchange, ticker: currentTicker, close: last.close },\n { headers: { "x-api-key": "YOUR_KEY" } } // 仅限私有代码\n);\nlogger.log("signal sent:", res.ok, res.status, res.data);\n')),Object(b.b)("h2",{id:"全局变量"},"全局变量"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"变量"),Object(b.b)("th",{parentName:"tr",align:null},"说明"),Object(b.b)("th",{parentName:"tr",align:null},"示例"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"currentExchange")),Object(b.b)("td",{parentName:"tr",align:null},"图表当前的交易所"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"binance"),", ",Object(b.b)("inlineCode",{parentName:"td"},"binanceFutures"),", ",Object(b.b)("inlineCode",{parentName:"td"},"coinbase"),", ...")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"currentTicker")),Object(b.b)("td",{parentName:"tr",align:null},"图表当前的交易对(格式取决于交易所)"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"BTCUSDT"),", ",Object(b.b)("inlineCode",{parentName:"td"},"ADA-USD"),", ",Object(b.b)("inlineCode",{parentName:"td"},"BTC/USDC"),", ...")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"currentTimeframe")),Object(b.b)("td",{parentName:"tr",align:null},"图表当前的周期"),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"1m"),", ",Object(b.b)("inlineCode",{parentName:"td"},"5m"),", ",Object(b.b)("inlineCode",{parentName:"td"},"15m"),", ...")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},"const candles = source.ohlcv(currentExchange, currentTicker, currentTimeframe);\nconst closes = candles.map(c => c.close);\n")),Object(b.b)("h2",{id:"日志"},"日志"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"logger"))," 类用于输出信息和调试。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"log(...args)")),Object(b.b)("td",{parentName:"tr",align:null},"向日志添加一条记录(有长度和数量限制)")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nlogger.log("First candle:", candles?.[0]);\n')),Object(b.b)(i.f,{src:"../../public/code_editor_log.png",mdxType:"Screenshot"}),Object(b.b)("h2",{id:"可视化"},"可视化"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"plot"))," 类负责绘制图形元素和数据序列。"),Object(b.b)("h3",{id:"几何图形"},"几何图形"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"box(title, date1, price1, date2, price2, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"矩形")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"square(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"正方形")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"diamond(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"菱形")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"triangle(title, date1, price1, size, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"三角形")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"circle(title, date1, price1, radius = 10, fill, opacity, stroke, strokeOpacity, strokeWidth)")),Object(b.b)("td",{parentName:"tr",align:null},"圆形")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"text(title, value, date1, price1, fontSize, fill, opacity)")),Object(b.b)("td",{parentName:"tr",align:null},"图表上的文字")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"table(title, rows, options)")),Object(b.b)("td",{parentName:"tr",align:null},"固定在图表角落的表格,参见 ",Object(b.b)("a",{parentName:"td",href:"#%E8%A1%A8%E6%A0%BC"},"表格"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"straightLine(title, date1, price1, date2, price2, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"直线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"horizontalLine(title, price1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"横贯整个图表的水平线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"verticalLine(title, date1, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"纵贯整个图表的垂直线")))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"参数"),Object(b.b)("th",{parentName:"tr",align:null},"数据类型"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"title")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"元素名称(图表上的唯一标识)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"date1")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number"),"(时间戳,毫秒)"),Object(b.b)("td",{parentName:"tr",align:null},"起始时间戳")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"price1")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"起始价格(Y 轴坐标)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"date2")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number"),"(时间戳,毫秒)"),Object(b.b)("td",{parentName:"tr",align:null},"结束时间戳(用于线和矩形)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"price2")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"结束价格(用于线和矩形)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"size")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"图形尺寸(像素)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"radius")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"圆的半径(默认 10)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string"),"(hex,例如 ",Object(b.b)("inlineCode",{parentName:"td"},'"#FF0000"'),")"),Object(b.b)("td",{parentName:"tr",align:null},"图形填充颜色")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number"),"(0–1)"),Object(b.b)("td",{parentName:"tr",align:null},"填充不透明度")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"stroke")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string"),"(hex,例如 ",Object(b.b)("inlineCode",{parentName:"td"},'"#000000"'),")"),Object(b.b)("td",{parentName:"tr",align:null},"描边颜色")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strokeOpacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number"),"(0–1)"),Object(b.b)("td",{parentName:"tr",align:null},"描边不透明度")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strokeWidth")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"描边宽度(像素)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"strokeDasharray")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"array"),"(例如 ",Object(b.b)("inlineCode",{parentName:"td"},"[5,5]"),")"),Object(b.b)("td",{parentName:"tr",align:null},"虚线样式")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fontSize")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")),Object(b.b)("td",{parentName:"tr",align:null},"文字大小(像素)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"value")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string")),Object(b.b)("td",{parentName:"tr",align:null},"文字内容(用于 ",Object(b.b)("inlineCode",{parentName:"td"},"text")," 方法)")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'plot.text("Text object", "Hello world!", 1757699100000, 115000, 10, "#00C8FF", 0.5);\nplot.straightLine(`${namePrefix} Open`, level.timeStart, level.open, level.timeEnd, level.open, color);\nplot.circle(`${namePrefix} High`, level.timeStart, level.high, 3, color);\n')),Object(b.b)("p",null,"图表上最多可显示 ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"3000"))," 个图形。"),Object(b.b)("h3",{id:"数据序列"},"数据序列"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"lineSeries(title, values, stroke, strokeOpacity, strokeWidth, strokeDasharray)")),Object(b.b)("td",{parentName:"tr",align:null},"折线图")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"barSeries(title, values, fill, opacity)")),Object(b.b)("td",{parentName:"tr",align:null},"柱状图")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"candleSeries(title, openValues, closeValues, highValues, lowValues, fill, opacity)")),Object(b.b)("td",{parentName:"tr",align:null},"K线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"areaSeries(title, values, fill, opacity, stroke, strokeOpacity, strokeWidth, base)")),Object(b.b)("td",{parentName:"tr",align:null},"线与 ",Object(b.b)("inlineCode",{parentName:"td"},"base"),"(默认:图表底部)之间的填充区域")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bandSeries(title, upperValues, lowerValues, fill, opacity, stroke, strokeOpacity, strokeWidth, step)")),Object(b.b)("td",{parentName:"tr",align:null},"两条序列之间的填充带,每根K线保留各自的颜色和不透明度")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"profile(title, values, options)")),Object(b.b)("td",{parentName:"tr",align:null},"可见K线的成交量分布式直方图,参见 ",Object(b.b)("a",{parentName:"td",href:"#%E5%88%86%E5%B8%83%E5%9B%BE"},"分布图"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"histogram(title, rows, options)")),Object(b.b)("td",{parentName:"tr",align:null},"以分布图形式绘制的现成价格映射,参见 ",Object(b.b)("a",{parentName:"td",href:"#%E7%9B%B4%E6%96%B9%E5%9B%BE"},"直方图"))))),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"参数"),Object(b.b)("th",{parentName:"tr",align:null},"数据类型"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"values"),", ",Object(b.b)("inlineCode",{parentName:"td"},"upperValues"),", ",Object(b.b)("inlineCode",{parentName:"td"},"lowerValues")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"(number \\| null)[]")),Object(b.b)("td",{parentName:"tr",align:null},"每根K线一个值,",Object(b.b)("inlineCode",{parentName:"td"},"null")," 隐藏该K线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill"),", ",Object(b.b)("inlineCode",{parentName:"td"},"stroke")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"string"),"(hex)或 ",Object(b.b)("inlineCode",{parentName:"td"},"function")),Object(b.b)("td",{parentName:"tr",align:null},"颜色,或返回该K线颜色的函数:",Object(b.b)("inlineCode",{parentName:"td"},"lineSeries"),"、",Object(b.b)("inlineCode",{parentName:"td"},"barSeries"),"、",Object(b.b)("inlineCode",{parentName:"td"},"candleSeries")," 和 ",Object(b.b)("inlineCode",{parentName:"td"},"areaSeries")," 为 ",Object(b.b)("inlineCode",{parentName:"td"},"(value, i)"),",",Object(b.b)("inlineCode",{parentName:"td"},"bandSeries")," 为 ",Object(b.b)("inlineCode",{parentName:"td"},"(upper, lower, i)"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number"),"(0–1)或 ",Object(b.b)("inlineCode",{parentName:"td"},"function")),Object(b.b)("td",{parentName:"tr",align:null},"填充不透明度,",Object(b.b)("inlineCode",{parentName:"td"},"areaSeries")," / ",Object(b.b)("inlineCode",{parentName:"td"},"bandSeries")," 可用函数 ",Object(b.b)("inlineCode",{parentName:"td"},"(value, i)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"(upper, lower, i)"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"base")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number")," ","|"," ",Object(b.b)("inlineCode",{parentName:"td"},"null")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"areaSeries")," 的基准线,",Object(b.b)("inlineCode",{parentName:"td"},"null")," = 图表底部")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"step")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"boolean")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bandSeries")," 样式:",Object(b.b)("inlineCode",{parentName:"td"},"true")," = 每根K线一列(默认),",Object(b.b)("inlineCode",{parentName:"td"},"false")," = 连续多边形")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'plot.lineSeries("EMA", ta.ema(closes, 20), "#00C8FF");\n// 每根K线保留各自的颜色:收盘价高于 EMA 为绿色,低于为红色\nplot.lineSeries("Close", closes, (v, i) => v > ema[i] ? colorBuy : colorSell);\nplot.barSeries("Premium %", premiumPercents, ((d) => d > 0 ? color1 : color2), 1);\nplot.candleSeries(\n "Candles",\n opens, closes, highs, lows,\n (v, i) => {\n return opens?.[i] > closes?.[i] ? colorBuy : colorSell\n }\n);\nplot.areaSeries("Volume", volumes, "#00C8FF", 0.3);\n// 按K线着色的区域,K线越大越不透明\nplot.areaSeries("Delta", deltas, (v, i) => v >= 0 ? colorBuy : colorSell, (v, i) => Math.min(1, Math.abs(v) / maxDelta));\n\n// 收盘价与其下方 1% 之间的压力带,按该K线的失衡比率着色和设置透明度\nplot.bandSeries(\n "Bid pressure",\n closes,\n closes.map(c => c * 0.99),\n (upper, lower, i) => ratios[i] > 0 ? bidColor : askColor,\n (upper, lower, i) => Math.abs(ratios[i]) / 100\n);\n')),Object(b.b)("p",null,"图表上最多可显示 ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"20"))," 条数据序列。"),Object(b.b)("h3",{id:"分布图"},"分布图"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"plot.profile(title, values, options?)")," 按价格绘制直方图,类似内置的成交量分布。",Object(b.b)("inlineCode",{parentName:"p"},"values[i]")," 是 ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()")," 第 ",Object(b.b)("inlineCode",{parentName:"p"},"i")," 根K线的价格映射:",Object(b.b)("inlineCode",{parentName:"p"},"{ price: value }")," 或 ",Object(b.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }"),"(可以直接传入 ",Object(b.b)("inlineCode",{parentName:"p"},"clusters()")," 或 ",Object(b.b)("inlineCode",{parentName:"p"},"liquidations()")," 记录的 ",Object(b.b)("inlineCode",{parentName:"p"},"data"),"),没有数据行的K线为 ",Object(b.b)("inlineCode",{parentName:"p"},"null"),"。",Object(b.b)("strong",{parentName:"p"},"图表上可见的K线")," 的数据行由图表本身按价格步长汇总,因此分布图会跟随平移、缩放和加载更多,无需重新运行。单个值用一种颜色绘制(负值使用 ",Object(b.b)("inlineCode",{parentName:"p"},"fill2"),"),买卖对会将柱子分为买入和卖出两部分,并支持 delta 模式。",Object(b.b)("inlineCode",{parentName:"p"},"profile()")," 不返回提醒句柄。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"选项"),Object(b.b)("th",{parentName:"tr",align:null},"默认值"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"step")),Object(b.b)("td",{parentName:"tr",align:null},"图表最小价格变动"),Object(b.b)("td",{parentName:"tr",align:null},"行高(价格单位),价格向下取整到该值")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"orient")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"right"')),Object(b.b)("td",{parentName:"tr",align:null},"柱子生长的起始边,",Object(b.b)("inlineCode",{parentName:"td"},'"right"')," 或 ",Object(b.b)("inlineCode",{parentName:"td"},'"left"'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"width")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"30")),Object(b.b)("td",{parentName:"tr",align:null},"最宽一行占图表宽度的百分比")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"#26a69a"')),Object(b.b)("td",{parentName:"tr",align:null},"数值或买入部分的颜色")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fill2")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"#ef5350"')),Object(b.b)("td",{parentName:"tr",align:null},"卖出部分的颜色")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0.6")),Object(b.b)("td",{parentName:"tr",align:null},"柱子不透明度")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"delta")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"绘制 ",Object(b.b)("inlineCode",{parentName:"td"},"buy - sell")," 而非总和,仅限买卖对")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"poc")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")),Object(b.b)("td",{parentName:"tr",align:null},"在数值最大的一行处画线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"valueArea")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"70")),Object(b.b)("td",{parentName:"tr",align:null},"POC 周围以完全不透明绘制的总量百分比,",Object(b.b)("inlineCode",{parentName:"td"},"false")," 表示禁用")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"valueAreaOpacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0.3")),Object(b.b)("td",{parentName:"tr",align:null},"价值区域之外各行的不透明度")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"labels")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"true")),Object(b.b)("td",{parentName:"tr",align:null},"空间足够时在柱子上显示行合计")))),Object(b.b)("p",null,"限制:每次运行 ",Object(b.b)("strong",{parentName:"p"},"3")," 个分布图,每根K线 ",Object(b.b)("strong",{parentName:"p"},"300")," 行,每个分布图 ",Object(b.b)("strong",{parentName:"p"},"200000")," 行。超出限制的行会被丢弃,运行日志中会记录一条说明。"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// 图表的成交量分布,与内置工具效果相同\nconst rows = await source.clusters();\nplot.profile("Volume", rows.map((r) => r?.data ?? null), { step: 5 });\n\n// 仅大额成交,按 delta 着色,位于左侧边缘\nconst minSize = input.number("Min trade size", 50, 0, 100000, 1);\nconst big = rows.map((r) => {\n if (!r?.data) return null;\n const out = {};\n for (const [price, c] of Object.entries(r.data)) {\n if (price === "totalBuy" || price === "totalSell") continue;\n if (c.buy + c.sell >= minSize) out[price] = { buy: c.buy, sell: c.sell };\n }\n return out;\n});\nplot.profile("Large trades", big, { step: 5, delta: true, orient: "left" });\n')),Object(b.b)("h3",{id:"直方图"},"直方图"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"plot.histogram(title, rows, options?)")," 绘制你已经构建好的直方图:",Object(b.b)("strong",{parentName:"p"},"整个图表只有一个价格映射"),",不会从K线中汇总任何数据。当数据行属于各根K线且图形应跟随可见范围时使用 ",Object(b.b)("inlineCode",{parentName:"p"},"profile()"),";当数据行是最终结果时使用 ",Object(b.b)("inlineCode",{parentName:"p"},"histogram()"),":订单簿快照、脚本计算出的价位、其他市场的数据。"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"rows")," 的格式与 ",Object(b.b)("inlineCode",{parentName:"p"},"profile()")," 的单根K线条目相同:",Object(b.b)("inlineCode",{parentName:"p"},"{ price: value }"),"、",Object(b.b)("inlineCode",{parentName:"p"},"{ price: { buy, sell } }")," 或 ",Object(b.b)("inlineCode",{parentName:"p"},"[price, buy, sell]")," 行的列表。单个值用一种颜色绘制(负值使用 ",Object(b.b)("inlineCode",{parentName:"p"},"fill2"),"),买卖对会将柱子分为买入和卖出两部分,并支持 delta 模式。选项与 ",Object(b.b)("inlineCode",{parentName:"p"},"profile()")," 相同,参见上表。"),Object(b.b)("p",null,"直方图以本次运行的最后一根K线作为日期,图表保留每个标题 ",Object(b.b)("strong",{parentName:"p"},"最新")," 的直方图,因此针对较早K线的部分运行(加载历史时)永远不会替换当前的直方图。每次脚本刷新时都会重绘,因此订单簿直方图会跟随实时订单簿。",Object(b.b)("inlineCode",{parentName:"p"},"histogram()")," 不返回提醒句柄。"),Object(b.b)("p",null,"限制:每次运行 ",Object(b.b)("strong",{parentName:"p"},"3")," 个直方图,",Object(b.b)("strong",{parentName:"p"},"5000")," 行。超出限制的行会被丢弃,运行日志中会记录一条说明。"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例,订单簿:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// 将实时订单簿作为右侧边缘的分布图:买盘用买入颜色,卖盘用卖出颜色\nconst book = await source.orderbook();\nconst rows = {};\nfor (const [price, qty] of Object.entries(book.bids)) rows[price] = { buy: qty };\nfor (const [price, qty] of Object.entries(book.asks)) rows[price] = { sell: qty };\nplot.histogram("Order book", rows, { step: 5, width: 25, valueArea: false, poc: false });\n')),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例,自定义价位:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// 自定义直方图:最近 100 根K线的集群成交量,越近的K线权重越大\nconst rows = await source.clusters();\nconst weighted = {};\nrows.slice(-100).forEach((r, i, arr) => {\n if (!r?.data) return;\n const weight = (i + 1) / arr.length;\n for (const [price, c] of Object.entries(r.data)) {\n if (price === "totalBuy" || price === "totalSell") continue;\n const cell = weighted[price] || (weighted[price] = { buy: 0, sell: 0 });\n cell.buy += (c.buy || 0) * weight;\n cell.sell += (c.sell || 0) * weight;\n }\n});\nplot.histogram("Weighted volume", weighted, { step: 5, orient: "left", delta: true });\n')),Object(b.b)("h3",{id:"表格"},"表格"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"plot.table(title, rows, options?)")," 绘制一个固定在图表面板角落的小网格:多周期汇总、已加载范围的统计、信号面板。",Object(b.b)("inlineCode",{parentName:"p"},"rows")," 是行数组,每行是单元格数组,单元格可以是字符串、数字或 ",Object(b.b)("inlineCode",{parentName:"p"},"{ text, color, bg, align, bold }"),"。同一角落的表格按顺序堆叠。表格以本次运行的最后一根K线作为日期,图表保留每个标题 ",Object(b.b)("strong",{parentName:"p"},"最新")," 的表格,因此针对较早K线的部分运行(加载历史时)永远不会替换当前的表格。宽度小于 500 px 的图表上不绘制表格。表格可以用鼠标拖动:位置随工作区保存,当脚本更改其 ",Object(b.b)("inlineCode",{parentName:"p"},"position")," 选项时重置。",Object(b.b)("inlineCode",{parentName:"p"},"table()")," 不返回提醒句柄。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"选项"),Object(b.b)("th",{parentName:"tr",align:null},"默认值"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"position")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"top-right"')),Object(b.b)("td",{parentName:"tr",align:null},"面板角落:",Object(b.b)("inlineCode",{parentName:"td"},'"top-right"'),"、",Object(b.b)("inlineCode",{parentName:"td"},'"top-left"'),"、",Object(b.b)("inlineCode",{parentName:"td"},'"bottom-right"'),"、",Object(b.b)("inlineCode",{parentName:"td"},'"bottom-left"'))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"header")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"false")),Object(b.b)("td",{parentName:"tr",align:null},"第一行加粗并绘制在阴影条上")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fontSize")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"11")),Object(b.b)("td",{parentName:"tr",align:null},"文字大小(px),8 到 16")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"color"),", ",Object(b.b)("inlineCode",{parentName:"td"},"bg"),", ",Object(b.b)("inlineCode",{parentName:"td"},"border")),Object(b.b)("td",{parentName:"tr",align:null},"随主题"),Object(b.b)("td",{parentName:"tr",align:null},"默认的文字、面板和网格颜色;单元格可以覆盖 ",Object(b.b)("inlineCode",{parentName:"td"},"color")," 和 ",Object(b.b)("inlineCode",{parentName:"td"},"bg"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"opacity")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"0.85")),Object(b.b)("td",{parentName:"tr",align:null},"面板不透明度")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"align")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},'"left"')),Object(b.b)("td",{parentName:"tr",align:null},"默认单元格对齐方式,",Object(b.b)("inlineCode",{parentName:"td"},'"left"'),"、",Object(b.b)("inlineCode",{parentName:"td"},'"center"')," 或 ",Object(b.b)("inlineCode",{parentName:"td"},'"right"'))))),Object(b.b)("p",null,"限制:每次运行 ",Object(b.b)("strong",{parentName:"p"},"3")," 个表格,",Object(b.b)("strong",{parentName:"p"},"50")," 行,",Object(b.b)("strong",{parentName:"p"},"10")," 列,每个单元格 ",Object(b.b)("strong",{parentName:"p"},"100")," 个字符。更长的文本会被截断并显示省略号,一列最多占图表宽度的 30%。"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = await source.ohlcv();\nconst closes = candles.map((c) => c.close);\nconst rsi = ta.rsi(closes, 14);\nconst last = rsi.at(-1);\nconst change = (closes.at(-1) / closes.at(-25) - 1) * 100;\n\nplot.table("Stats", [\n ["Metric", "Value"],\n ["RSI 14", { text: last.toFixed(1), color: last > 70 ? "#ef5350" : last < 30 ? "#26a69a" : undefined }],\n ["Change 24 bars", { text: change.toFixed(2) + "%", align: "right" }],\n ["Volume", candles.slice(-24).reduce((s, c) => s + c.volume, 0).toFixed(0)],\n], { position: "top-right", header: true });\n')),Object(b.b)("h2",{id:"技术分析"},"技术分析"),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"ta"))," 类实现了 PineScript v5 的 ",Object(b.b)("inlineCode",{parentName:"p"},"ta.*")," 函数。Pine 逐根K线计算,而这里的每个函数都接收完整的序列(数组,每根K线一个值,从旧到新),并返回相同长度的序列,可直接绘制。在周期尚未填满时值为 ",Object(b.b)("inlineCode",{parentName:"p"},"null"),",",Object(b.b)("inlineCode",{parentName:"p"},"null")," 输入会像 Pine 的 ",Object(b.b)("inlineCode",{parentName:"p"},"na")," 一样传播。隐式读取 ",Object(b.b)("inlineCode",{parentName:"p"},"high"),"、",Object(b.b)("inlineCode",{parentName:"p"},"low"),"、",Object(b.b)("inlineCode",{parentName:"p"},"close")," 或 ",Object(b.b)("inlineCode",{parentName:"p"},"volume")," 的 Pine 函数在这里将这些数组作为参数传入。"),Object(b.b)("p",null,"返回多条序列的函数(",Object(b.b)("inlineCode",{parentName:"p"},"bb"),"、",Object(b.b)("inlineCode",{parentName:"p"},"kc"),"、",Object(b.b)("inlineCode",{parentName:"p"},"macd"),"、",Object(b.b)("inlineCode",{parentName:"p"},"stoch"),"、",Object(b.b)("inlineCode",{parentName:"p"},"dmi"),"、",Object(b.b)("inlineCode",{parentName:"p"},"supertrend"),")返回一个同时带有命名属性的数组:",Object(b.b)("inlineCode",{parentName:"p"},"const [middle, upper, lower] = ta.bb(closes, 20, 2)")," 或 ",Object(b.b)("inlineCode",{parentName:"p"},"ta.bb(closes, 20, 2).upper"),"。"),Object(b.b)("h3",{id:"辅助函数"},"辅助函数"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"highest(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"lowest(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"length")," 根K线内的最高 / 最低值")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"highestbars(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"lowestbars(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"到最高 / 最低K线的偏移量(0 或负数)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"max(values)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"min(values)")),Object(b.b)("td",{parentName:"tr",align:null},"截至每根K线的历史最高 / 最低值")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"range(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"highest - lowest"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"change(values, length = 1)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"values[i] - values[i - length]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"mom(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"动量")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"roc(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"变化率,%")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cum(values)")),Object(b.b)("td",{parentName:"tr",align:null},"累计和")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"rising(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"falling(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"值高于 / 低于之前 ",Object(b.b)("inlineCode",{parentName:"td"},"length")," 个值中的每一个")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"variance(values, length, biased = true)")),Object(b.b)("td",{parentName:"tr",align:null},"方差")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"stdev(values, length, biased = true)")),Object(b.b)("td",{parentName:"tr",align:null},"标准差")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"dev(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"平均绝对偏差")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"median(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"中位数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"mode(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"众数(出现次数相同时取最小值)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"percentile_linear_interpolation(values, length, percentage)")),Object(b.b)("td",{parentName:"tr",align:null},"百分位数,在两个最近排名之间线性插值")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"percentile_nearest_rank(values, length, percentage)")),Object(b.b)("td",{parentName:"tr",align:null},"百分位数,最近排名法")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"percentrank(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"之前 ",Object(b.b)("inlineCode",{parentName:"td"},"length")," 个值中小于或等于当前值的百分比")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"correlation(series1, series2, length)")),Object(b.b)("td",{parentName:"tr",align:null},"相关系数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"crossover(series1, series2)")),Object(b.b)("td",{parentName:"tr",align:null},"向上交叉(任一参数都可以是数字:",Object(b.b)("inlineCode",{parentName:"td"},"ta.crossover(rsi, 70)"),")")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"crossunder(series1, series2)")),Object(b.b)("td",{parentName:"tr",align:null},"向下交叉")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cross(series1, series2)")),Object(b.b)("td",{parentName:"tr",align:null},"任意交叉")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"barssince(condition)")),Object(b.b)("td",{parentName:"tr",align:null},"距 ",Object(b.b)("inlineCode",{parentName:"td"},"condition"),"(布尔数组)上次为真的K线数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"valuewhen(condition, values, occurrence = 0)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"condition")," 在第 ",Object(b.b)("inlineCode",{parentName:"td"},"occurrence")," 次之前为真时 ",Object(b.b)("inlineCode",{parentName:"td"},"values")," 的值")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"pivothigh(values, leftbars, rightbars)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"pivotlow(...)")),Object(b.b)("td",{parentName:"tr",align:null},"确认K线上的枢轴值,枢轴本身位于 ",Object(b.b)("inlineCode",{parentName:"td"},"rightbars")," 根K线之前")))),Object(b.b)("h3",{id:"移动平均线"},"移动平均线"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"简单移动平均线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"ema(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"指数移动平均线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"rma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Wilder 移动平均线(RSI / ATR 使用)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"加权移动平均线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"hma(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"Hull 移动平均线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"alma(values, length, offset = 0.85, sigma = 6, floor = false)")),Object(b.b)("td",{parentName:"tr",align:null},"Arnaud Legoux 移动平均线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"swma(values)")),Object(b.b)("td",{parentName:"tr",align:null},"4 根K线的对称加权移动平均线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"vwma(values, volumes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"成交量加权移动平均线")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"linreg(values, length, offset = 0)")),Object(b.b)("td",{parentName:"tr",align:null},"线性回归曲线")))),Object(b.b)("h3",{id:"振荡指标"},"振荡指标"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"rsi(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"相对强弱指数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cmo(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"钱德动量摆动指标")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cog(values, length)")),Object(b.b)("td",{parentName:"tr",align:null},"重心指标")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"mfi(values, volumes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"资金流量指数(",Object(b.b)("inlineCode",{parentName:"td"},"values")," 通常为 hlc3)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tsi(values, shortLength, longLength)")),Object(b.b)("td",{parentName:"tr",align:null},"真实强度指数,-1..1")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wpr(highs, lows, closes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"威廉指标 %R")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"stoch(highs, lows, closes, period = 14, smoothK = 3, smoothD = 3)")),Object(b.b)("td",{parentName:"tr",align:null},"随机指标 ",Object(b.b)("inlineCode",{parentName:"td"},"[k, d]"),",",Object(b.b)("inlineCode",{parentName:"td"},"smoothK = 1")," 得到原始值")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"cci(values, length)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"cci(highs, lows, closes, length)")),Object(b.b)("td",{parentName:"tr",align:null},"顺势指标(第二种形式基于典型价格)")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"macd(values, fast = 12, slow = 26, signalPeriod = 9)")),Object(b.b)("td",{parentName:"tr",align:null},"MACD ",Object(b.b)("inlineCode",{parentName:"td"},"[macd, signal, histogram]"))))),Object(b.b)("h3",{id:"通道与带状指标"},"通道与带状指标"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bb(values, length = 20, mult = 2)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"bollinger(...)")),Object(b.b)("td",{parentName:"tr",align:null},"布林带 ",Object(b.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bbw(values, length, mult)")),Object(b.b)("td",{parentName:"tr",align:null},"布林带宽度 ",Object(b.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"kc(values, highs, lows, closes, length = 20, mult = 2, useTrueRange = true)")),Object(b.b)("td",{parentName:"tr",align:null},"肯特纳通道 ",Object(b.b)("inlineCode",{parentName:"td"},"[middle, upper, lower]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"kcw(values, highs, lows, closes, length, mult, useTrueRange)")),Object(b.b)("td",{parentName:"tr",align:null},"肯特纳通道宽度 ",Object(b.b)("inlineCode",{parentName:"td"},"(upper - lower) / middle"))))),Object(b.b)("h3",{id:"趋势与波动率"},"趋势与波动率"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"tr(highs, lows, closes, handleNa = false)")),Object(b.b)("td",{parentName:"tr",align:null},"真实波幅(",Object(b.b)("inlineCode",{parentName:"td"},"handleNa = true")," 时第一根K线为 ",Object(b.b)("inlineCode",{parentName:"td"},"high - low"),")")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"atr(highs, lows, closes, period = 14)")),Object(b.b)("td",{parentName:"tr",align:null},"平均真实波幅")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"dmi(highs, lows, closes, diLength = 14, adxSmoothing = 14)")),Object(b.b)("td",{parentName:"tr",align:null},"趋向指标 ",Object(b.b)("inlineCode",{parentName:"td"},"[plus, minus, adx]"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"adx(highs, lows, closes, period = 14)")),Object(b.b)("td",{parentName:"tr",align:null},"平均趋向指数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sar(highs, lows, closes, start = 0.02, inc = 0.02, max = 0.2)")),Object(b.b)("td",{parentName:"tr",align:null},"抛物线 SAR")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"supertrend(highs, lows, closes, factor = 3, atrPeriod = 10)")),Object(b.b)("td",{parentName:"tr",align:null},"超级趋势 ",Object(b.b)("inlineCode",{parentName:"td"},"[supertrend, direction]"),",direction ",Object(b.b)("inlineCode",{parentName:"td"},"-1")," = 上升趋势,",Object(b.b)("inlineCode",{parentName:"td"},"1")," = 下降趋势")))),Object(b.b)("h3",{id:"成交量"},"成交量"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"vwap(values, volumes, anchor?)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"vwap(highs, lows, closes, volumes, anchor?)")),Object(b.b)("td",{parentName:"tr",align:null},"累计 VWAP(第二种形式基于典型价格),在 ",Object(b.b)("inlineCode",{parentName:"td"},"anchor"),"(布尔数组)为真的K线上重新开始")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"obv(closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"能量潮")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"accdist(highs, lows, closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"累积 / 派发")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"iii(highs, lows, closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"日内强度指数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"pvt(closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"量价趋势")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"nvi(closes, volumes)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"pvi(closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"负 / 正成交量指数")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wad(highs, lows, closes)")),Object(b.b)("td",{parentName:"tr",align:null},"威廉累积 / 派发")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"wvad(opens, highs, lows, closes, volumes)")),Object(b.b)("td",{parentName:"tr",align:null},"威廉变异累积 / 派发")))),Object(b.b)("h3",{id:"订单簿辅助函数"},"订单簿辅助函数"),Object(b.b)("p",null,Object(b.b)("inlineCode",{parentName:"p"},"orderbook")," 为 ",Object(b.b)("inlineCode",{parentName:"p"},"source.orderbook()")," 或 ",Object(b.b)("inlineCode",{parentName:"p"},"source.depths()[i].data"),":",Object(b.b)("inlineCode",{parentName:"p"},"{asks: {price: quantity}, bids: {price: quantity}}"),"。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"orderbookSide(orderbook, side)")),Object(b.b)("td",{parentName:"tr",align:null},"一侧(",Object(b.b)("inlineCode",{parentName:"td"},"'bids'")," / ",Object(b.b)("inlineCode",{parentName:"td"},"'asks'"),")作为 ",Object(b.b)("inlineCode",{parentName:"td"},"[[price, quantity], ...]"),",按最优价格优先排序")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"bestBid(orderbook)")," / ",Object(b.b)("inlineCode",{parentName:"td"},"bestAsk(orderbook)")),Object(b.b)("td",{parentName:"tr",align:null},"最优买价 / 卖价(空订单簿为 ",Object(b.b)("inlineCode",{parentName:"td"},"null"),")")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sumBids(orderbook, percent, price, inQuote)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"price"),"(默认:最优买价)与 ",Object(b.b)("inlineCode",{parentName:"td"},"price * (1 - percent / 100)")," 之间的累计买盘数量,",Object(b.b)("inlineCode",{parentName:"td"},"inQuote = true")," 时累加 ",Object(b.b)("inlineCode",{parentName:"td"},"price * quantity"))),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"sumAsks(orderbook, percent, price, inQuote)")),Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"price"),"(默认:最优卖价)与 ",Object(b.b)("inlineCode",{parentName:"td"},"price * (1 + percent / 100)")," 之间的累计卖盘数量")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nconst rsiValues = ta.rsi(closes, 14);\nplot.lineSeries("RSI", rsiValues, "#00C8FF");\n')),Object(b.b)("h2",{id:"提醒"},"提醒"),Object(b.b)("p",null,"用户可以在图表上指标设置的 ",Object(b.b)("strong",{parentName:"p"},"提醒")," 选项卡中为你的指标创建提醒。\n提醒会在服务器端定期检查,通知发送到 ",Object(b.b)("strong",{parentName:"p"},"Telegram")," 和/或用户定义的 ",Object(b.b)("strong",{parentName:"p"},"Webhook URL"),"。"),Object(b.b)("h3",{id:"提醒设置--alertinput"},"提醒设置 — ",Object(b.b)("inlineCode",{parentName:"h3"},"alertInput")),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"alertInput"))," 类声明提醒设置。它的用法与 ",Object(b.b)("inlineCode",{parentName:"p"},"input")," 完全相同,但字段显示在 ",Object(b.b)("strong",{parentName:"p"},"提醒")," 选项卡中,每个用户都为自己的提醒配置各自的值。"),Object(b.b)("p",null,"没有 ",Object(b.b)("inlineCode",{parentName:"p"},"alertInput")," 声明的脚本无法用于提醒。"),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"number(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"数值输入")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"range(title, defaultValue, min, max, step)")),Object(b.b)("td",{parentName:"tr",align:null},"范围输入")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"select(title, defaultValue, values)")),Object(b.b)("td",{parentName:"tr",align:null},"下拉选择")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"color(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"颜色选择器")),Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"boolean(title, defaultValue)")),Object(b.b)("td",{parentName:"tr",align:null},"布尔输入")))),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const alertVolumeThreshold = alertInput.number("Volume threshold", 1000, 0, 10000000, 1);\n')),Object(b.b)("h3",{id:"触发提醒--alertfire"},"触发提醒 — ",Object(b.b)("inlineCode",{parentName:"h3"},"alert.fire")),Object(b.b)("table",null,Object(b.b)("thead",{parentName:"table"},Object(b.b)("tr",{parentName:"thead"},Object(b.b)("th",{parentName:"tr",align:null},"方法"),Object(b.b)("th",{parentName:"tr",align:null},"说明"))),Object(b.b)("tbody",{parentName:"table"},Object(b.b)("tr",{parentName:"tbody"},Object(b.b)("td",{parentName:"tr",align:null},Object(b.b)("inlineCode",{parentName:"td"},"fire(title, message, date)")),Object(b.b)("td",{parentName:"tr",align:null},"触发提醒通知")))),Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},"三个参数都是 ",Object(b.b)("strong",{parentName:"li"},"必需的")," — 缺少 ",Object(b.b)("inlineCode",{parentName:"li"},"title"),"、",Object(b.b)("inlineCode",{parentName:"li"},"message")," 或 ",Object(b.b)("inlineCode",{parentName:"li"},"date")," 的调用会被跳过(并在日志中写入警告)。"),Object(b.b)("li",{parentName:"ul"},"保持提醒 ",Object(b.b)("strong",{parentName:"li"},"标题固定"),",不要生成唯一标题。每个标题每次运行只触发一次(每次运行最多 ",Object(b.b)("strong",{parentName:"li"},"20")," 个标题)。"),Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"date")," 是信号所属K线的 ",Object(b.b)("inlineCode",{parentName:"li"},"startTime"),":同一标题只有在针对 ",Object(b.b)("strong",{parentName:"li"},"更新的")," K线触发时才会再次通知。早于用户创建提醒时刻的K线信号会被忽略(防刷屏)。")),Object(b.b)("p",null,Object(b.b)("strong",{parentName:"p"},"示例:")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'if (candle.volume > alertVolumeThreshold) {\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n}\n')),Object(b.b)("h3",{id:"图形提醒--plotshapealert"},"图形提醒 — ",Object(b.b)("inlineCode",{parentName:"h3"},"plot.(...).alert(...)")),Object(b.b)("p",null,"所有几何图形(",Object(b.b)("inlineCode",{parentName:"p"},"box"),"、",Object(b.b)("inlineCode",{parentName:"p"},"square"),"、",Object(b.b)("inlineCode",{parentName:"p"},"diamond"),"、",Object(b.b)("inlineCode",{parentName:"p"},"triangle"),"、",Object(b.b)("inlineCode",{parentName:"p"},"circle"),"、",Object(b.b)("inlineCode",{parentName:"p"},"straightLine"),"、",Object(b.b)("inlineCode",{parentName:"p"},"horizontalLine"),"、",Object(b.b)("inlineCode",{parentName:"p"},"verticalLine"),"、",Object(b.b)("inlineCode",{parentName:"p"},"text"),")都返回一个带有 ",Object(b.b)("inlineCode",{parentName:"p"},".alert()")," 方法的句柄。\n提醒会自动使用图形的 ",Object(b.b)("inlineCode",{parentName:"p"},"date1")," 触发,因此防刷屏逻辑无需额外代码即可生效 — 这是针对逐根K线信号的推荐方式。"),Object(b.b)("p",null,"两种形式:"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'// 简单形式:每当图形针对新日期绘制时触发\nplot.box(...).alert("High volume", `vol ${candle.volume}`);\n\n// 回调形式:不返回任何内容则跳过,返回 [title, message] 则触发\nplot.box(...).alert((shape) => {\n if (candle.volume > alertVolumeThreshold)\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n});\n')),Object(b.b)("p",null,"回调接收图形数据(",Object(b.b)("inlineCode",{parentName:"p"},"date1"),"、",Object(b.b)("inlineCode",{parentName:"p"},"price1"),"、",Object(b.b)("inlineCode",{parentName:"p"},"date2"),"、",Object(b.b)("inlineCode",{parentName:"p"},"price2")," 等)。"),Object(b.b)("h3",{id:"序列提醒--plotseriesalert"},"序列提醒 — ",Object(b.b)("inlineCode",{parentName:"h3"},"plot.(...).alert(...)")),Object(b.b)("p",null,"数据序列(",Object(b.b)("inlineCode",{parentName:"p"},"lineSeries"),"、",Object(b.b)("inlineCode",{parentName:"p"},"barSeries"),"、",Object(b.b)("inlineCode",{parentName:"p"},"candleSeries"),"、",Object(b.b)("inlineCode",{parentName:"p"},"areaSeries"),"、",Object(b.b)("inlineCode",{parentName:"p"},"bandSeries"),")同样返回 ",Object(b.b)("inlineCode",{parentName:"p"},".alert()")," 句柄。\n回调接收 ",Object(b.b)("strong",{parentName:"p"},"最新的数据点")," 和最新K线的日期,提醒以该日期触发。"),Object(b.b)("ul",null,Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"lineSeries")," / ",Object(b.b)("inlineCode",{parentName:"li"},"barSeries")," / ",Object(b.b)("inlineCode",{parentName:"li"},"areaSeries")," — 回调接收最后一个 ",Object(b.b)("strong",{parentName:"li"},"值"),"(数字)"),Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"candleSeries")," — 回调接收最后一根K线 ",Object(b.b)("inlineCode",{parentName:"li"},"{open, close, high, low}")),Object(b.b)("li",{parentName:"ul"},Object(b.b)("inlineCode",{parentName:"li"},"bandSeries")," — 回调接收最后的 ",Object(b.b)("inlineCode",{parentName:"li"},"{upper, lower}"))),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'plot.lineSeries("RSI", rsiValues, color).alert((rsi, date) => {\n if (rsi > alertRsiThreshold) alert.fire("RSI high", `RSI ${rsi.toFixed(1)}`, latestCandle.startTime);\n});\n')),Object(b.b)("p",null,"持续为真的条件在每根 ",Object(b.b)("strong",{parentName:"p"},"新K线")," 上通知一次。对于一次性信号,请使用交叉类条件(",Object(b.b)("inlineCode",{parentName:"p"},"ta.crossover"),")。"),Object(b.b)("h3",{id:"完整示例"},"完整示例"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Volume alerts";\nconst description = "Shows boxes on high-volume candles";\ndefine(title, description, "onchart", true, true);\n\nconst color = style.color("Color", "#00C8FF");\nconst volumeThreshold = input.number("Volume threshold", 1000, 0, 10000000, 1);\nconst alertVolumeThreshold = alertInput.number("Alert volume threshold", 5000, 0, 10000000, 1);\nconst alertCloseThreshold = alertInput.number("Alert close threshold", 100000, 0, 10000000, 1);\n\nconst candles = source.ohlcv();\nconst latestCandle = candles.at(-1);\nconst closes = candles.map(c => c.close);\n\n// 序列提醒:检查最新收盘价\nplot.lineSeries("Closes", closes, color).alert((close, date) => {\n if (close > alertCloseThreshold) alert.fire("Close above threshold", `close ${close}`, latestCandle.startTime);\n});\n\nfor (let i = 0; i < candles.length; i++) {\n const candle = candles[i];\n\n if (candle.volume > volumeThreshold) {\n const right = i < candles.length - 1 ? candles[i + 1].startTime : candle.startTime + 60000;\n\n // 图形提醒:与用户的提醒阈值进行比较\n plot.box(`Volume ${i}`, candle.startTime, candle.high, right, candle.low, "#00C8FF", 0.3)\n .alert(() => {\n if (candle.volume > alertVolumeThreshold)\n alert.fire("High volume", `vol ${candle.volume}`, candle.startTime);\n });\n }\n}\n')),Object(b.b)("h2",{id:"指标示例"},"指标示例"),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Your first indicator";\nconst description = "Shows closes lines on the chart";\nconst indicatorType = "onchart";\n\ndefine(title, description, indicatorType, true, true);\n\nconst color = input.color("Line Color", "#00C8FF");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nplot.lineSeries("Closes", closes, color);\n\n')),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'define("Example Indicator", "Demonstrates basic plotting", "onchart", true, true);\n\nconst color = input.color("Line Color", "#00FF99");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\n\nconst ema20 = ta.ema(closes, 20);\nplot.lineSeries("EMA 20", ema20, color);\n\n')),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Colored Volume Bars"; \nconst description = "Volumes colored based on candle direction."; \nconst indicatorType = "onchart"; \nconst isPublic = true; \nconst isPublicCode = true; \n\ndefine(title, description, indicatorType, isPublic, isPublicCode); \n\n// 获取 OHLC K线\nconst candles = source.ohlcv(); \n\nconst colorUp = style.color("Color 1", "#2BB462"); // 上涨使用的绿色\nconst colorDown = style.color("Color 2", "#FB4C51"); // 下跌使用的红色\nconst volumes = candles.map(candle => candle.volume); \n\nplot.barSeries("Volume", volumes, (value, index) => {\n const currentCandle = candles[index]; \n return currentCandle.close >= currentCandle.open ? colorUp : colorDown; \n});\n\n')),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},"define('Coinbase Premium Index', 'Coinbase Premium Index', 'offchart', true, false);\n\nconst color1 = style.color(\"Color 1\", \"#2BB462\");\nconst color2 = style.color(\"Color 2\", \"#FB4C51\");\n\n// 获取 OHLC K线\nconst cbCandles = source.ohlcv('coinbase', 'BTC-USD');\nconst binanceCandles = source.ohlcv('binance', 'BTCUSDT');\n\n// 提取收盘价\nconst cbCloses = cbCandles.map(c => c.close);\nconst binanceCloses = binanceCandles.map(c => c.close);\n\n// --- Coinbase 溢价指数计算 ---\nconst premiumPercent = cbCloses.map((cb, i) => {\n const b = binanceCloses[i];\n return ((cb - b) / b) * 100;\n});\n\n// 绘制溢价指数\nplot.barSeries(\"Premium %\", premiumPercent, ((d) => d > 0 ? color1 : color2)) // 百分比差值\n\n")),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Candles";\nconst description = "Simple candles draw";\nconst indicatorType = "offchart";\nconst isPublic = true;\nconst isPublicCode = true;\ndefine(title, description, indicatorType, isPublic, isPublicCode);\n\nconst colorBuy = style.color("Buy Color", "#2BB462");\nconst colorSell = style.color("Sell Color", "#7a3d3f");\nconst candles = source.ohlcv();\nconst closes = candles.map(c => c.close);\nconst opens = candles.map(c => c.open);\nconst highs = candles.map(c => c.high);\nconst lows = candles.map(c => c.low);\nplot.candleSeries(\n "Candles",\n opens, closes, highs, lows,\n (v, i) => {\n return opens?.[i] > closes?.[i] ? colorBuy : colorSell\n }\n);\n\n')),Object(b.b)("p",null,'Order Book Pressure(价格周围的买卖盘深度失衡带,类似交易终端中的 "Order Book Pressure" 叠加层):'),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'const title = "Order Book Pressure";\nconst description = "Bid / ask depth imbalance bands around the price";\ndefine(title, description, "onchart", true, true);\n\nconst minBidRatio = input.number("Min bid ratio %", 20, 0, 100, 1);\nconst minAskRatio = input.number("Min ask ratio %", 20, 0, 100, 1);\nconst depthFrom = input.select("Depth from", "0%", ["0%", "1%", "2.5%", "5%"]);\nconst depthTo = input.select("Depth to", "5%", ["1%", "2.5%", "5%", "10%"]);\n\nconst bidColor = style.color("Bid fill color", "#a5d6a7");\nconst askColor = style.color("Ask fill color", "#f1627e");\nconst extremeColor = style.color("Extreme color", "#ffff00");\nconst highlight = style.boolean("Highlight extremes", true);\nconst showRef = style.boolean("Show reference lines", true);\n\nconst alertMinRatio = alertInput.number("Alert min |ratio| %", 40, 0, 100, 1);\n\nconst bounds = [1, 2.5, 5, 10]; // 距收盘价的深度区间,%\nconst from = parseFloat(depthFrom);\nconst to = parseFloat(depthTo);\n\nconst candles = source.ohlcv();\nconst depths = source.depths();\nconst liveBook = source.orderbook();\n\n// 每根K线的订单簿:depths()[i] 是 candles[i] 的快照(最大的限价单),最新K线使用实时订单簿\nconst lastIndex = candles.length - 1;\nconst books = candles.map((c, i) => {\n if (!c) return null;\n if (i === lastIndex && ta.bestBid(liveBook)) return liveBook;\n return depths[i]?.data || null;\n});\nconst closes = candles.map(c => c ? c.close : null);\n\n// 每个区间的失衡比率,%(正值 = 买盘占优,负值 = 卖盘占优)\nconst ratios = bounds.map((upper, b) => {\n const lower = b === 0 ? 0 : bounds[b - 1];\n return candles.map((c, i) => {\n const book = books[i];\n if (!c || !book) return null;\n const bid = ta.sumBids(book, upper, c.close) - ta.sumBids(book, lower, c.close);\n const ask = ta.sumAsks(book, upper, c.close) - ta.sumAsks(book, lower, c.close);\n const total = bid + ask;\n return total > 0 ? ((bid - ask) / total) * 100 : 0;\n });\n});\n\n// 比率越强 -> 带越不透明,极端比率使用极端颜色\nconst bandOpacity = (ratio) => Math.min(0.95, Math.abs(ratio || 0) / 70 * 0.95);\nconst bandColor = (ratio) => highlight && Math.abs(ratio || 0) >= 63 ? extremeColor : (ratio >= 0 ? bidColor : askColor);\n\nbounds.forEach((upper, b) => {\n const lower = b === 0 ? 0 : bounds[b - 1];\n if (from > lower || upper > to) return; // 该区间不在所选深度范围内\n\n const bidUpper = closes.map(c => c != null ? c * (1 - lower / 100) : null);\n const bidLower = closes.map(c => c != null ? c * (1 - upper / 100) : null);\n const askLower = closes.map(c => c != null ? c * (1 + lower / 100) : null);\n const askUpper = closes.map(c => c != null ? c * (1 + upper / 100) : null);\n\n if (showRef) {\n plot.lineSeries(`Bid ${upper}%`, bidLower, bidColor, 0.4);\n plot.lineSeries(`Ask ${upper}%`, askUpper, askColor, 0.4);\n }\n\n // 买盘压力:仅在买盘占优超过最小比率的K线上填充该带\n plot.bandSeries(\n `Bid pressure ${lower}-${upper}%`,\n bidUpper.map((v, i) => ratios[b][i] >= minBidRatio ? v : null),\n bidLower,\n (upper, lower, i) => bandColor(ratios[b][i]),\n (upper, lower, i) => bandOpacity(ratios[b][i])\n );\n\n // 卖盘压力\n plot.bandSeries(\n `Ask pressure ${lower}-${upper}%`,\n askUpper.map((v, i) => ratios[b][i] <= -minAskRatio ? v : null),\n askLower,\n (upper, lower, i) => bandColor(ratios[b][i]),\n (upper, lower, i) => bandOpacity(ratios[b][i])\n );\n\n // 最新K线上的提醒\n const latestRatio = ratios[b][lastIndex];\n if (latestRatio != null && Math.abs(latestRatio) >= alertMinRatio) {\n alert.fire(`Pressure ${lower}-${upper}%`, `ratio ${latestRatio.toFixed(1)}%`, candles[lastIndex].startTime);\n }\n});\n\n')))}void 0!==m&&m&&m===Object(m)&&Object.isExtensible(m)&&!Object.prototype.hasOwnProperty.call(m,"__filemeta")&&Object.defineProperty(m,"__filemeta",{configurable:!0,value:{name:"MDXContent",filename:"src/components/zh/Scripting.mdx"}}),m.isMDXComponent=!0}}]); //# sourceMappingURL=component---src-components-zh-scripting-mdx-912a65a3ef868b96e1d6.js.map