(window.webpackJsonp=window.webpackJsonp||[]).push([[77],{Iunp: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/ko/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는 시장 데이터(캔들, 오더북, 클러스터, 청산, 파생상품 데이터), 플로팅 기본 요소, 기술적 분석 헬퍼와 알림을 제공합니다."),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개 캔들"),"보다 더 과거를 볼 수 없습니다."),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"},"계산 범위.")," 기본적으로 스크립트는 차트에서 계산이 필요한 부분만 계산합니다. 즉, 뒤로 스크롤하여 로드된 바 또는 새로고침 시 최신 바와 함께, 계산에는 필요하지만 반환되지는 않는 그 이전의 ",Object(b.b)("strong",{parentName:"p"},Object(b.b)("inlineCode",{parentName:"strong"},"warmup"))," 바(기본값 500)만큼의 히스토리를 계산합니다. 지표에 더 많거나 적은 히스토리가 필요하면 ",Object(b.b)("inlineCode",{parentName:"p"},"warmup"),"을 선언하세요. 예를 들어 EMA(200)에는 ",Object(b.b)("inlineCode",{parentName:"p"},"{ warmup: 200 }"),"을 사용합니다. 값이나 도형이 ",Object(b.b)("strong",{parentName:"p"},"보이는 전체 범위"),"에 의존하는 스크립트(첫 번째 보이는 캔들부터의 VWAP, 누적 델타, 화면 내 최댓값의 라벨, 차트 전체에 그려지는 레벨)는 반드시 ",Object(b.b)("inlineCode",{parentName:"p"},"{ fullRange: true }"),"를 선언해야 하며, 그렇지 않으면 히스토리를 더 로드한 후 결과가 잘못됩니다. 이 모드는 스크립트를 저장할 때마다 ",Object(b.b)("inlineCode",{parentName:"p"},"define()"),"에서 읽힙니다. ",Object(b.b)("inlineCode",{parentName:"p"},"fullRange")," 없이 저장된 스크립트는 부분적으로 계산되므로, 기존의 누적 스크립트를 편집할 때 이 플래그를 추가하세요. 부분 스크립트는 나뉘어서 로드되기도 합니다. 긴 히스토리에서 스크립트를 켜면 차트는 먼저 최신 500개 캔들(",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"))," 클래스는 서버에서 시장 데이터를 가져옵니다. 캔들 기반 메서드는 동일한 매개변수를 받으며, 두 가지 실시간 스냅샷은 다릅니다. ",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},"현재 날짜로부터의 히스토리 바 개수, ",Object(b.b)("strong",{parentName:"td"},"최대 5000"),".")))),Object(b.b)(i.b,{type:"note",title:"데이터는 차트 캔들에 맞춰 정렬됩니다",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"},"차트 캔들당 하나의 항목"),"을 반환합니다. ",Object(b.b)("inlineCode",{parentName:"p"},"depths()[i]"),"는 ",Object(b.b)("inlineCode",{parentName:"p"},"ohlcv()[i]"),"의 오더북이고, ",Object(b.b)("inlineCode",{parentName:"p"},"moreData()[i]"),"는 그 캔들의 파생상품 데이터를 담는 식입니다. 소스에 해당 캔들의 기록이 없으면(예: 오더북 히스토리가 캔들 히스토리보다 짧은 경우) 항목은 ",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()"),"에는 서버가 이미 로드한 캔들만 포함되며 ",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,"캔들 데이터."),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,"캔들당 하나씩의 과거 오더북 스냅샷입니다. 가장 큰 지정가 주문만 저장됩니다(히트맵의 기반 데이터)."),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,"클러스터(풋프린트) 데이터: 캔들의 모든 가격 레벨별 매수 및 매도 거래량입니다."),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,"캔들의 모든 가격 레벨별 청산 거래량입니다(선물 시장만 해당). 형식은 ",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,"캔들별 파생상품 데이터: 펀딩비, 미결제약정 캔들, 롱/숏 비율입니다(선물 시장만 해당)."),Object(b.b)("pre",null,Object(b.b)("code",{parentName:"pre",className:"language-js"},'[\n { \n "data": {\n "FR": 0.00003777, // 펀딩비\n "OI": { // 미결제약정 캔들\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,"실시간 오더북 스냅샷: 캔들에 묶이지 않은 현재 전체 오더북입니다."),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"),", ...)를 사용하세요.\n캔들의 과거 오더북은 ",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"},"유동성 스크리너"),"의 레벨: 거래소의 대형 대기 지정가 주문을 스크리너 페이지와 동일한 설정으로 필터링한 것입니다. 캔들에 묶이지 않은 실시간 데이터입니다. 플랜이 없으면 근접도는 1%, 지속 시간은 60분, 결과는 200개 레벨로 제한되며, 플랜이 있으면 최대 2000개 레벨까지 가능합니다. 가장 큰 주문이 먼저 옵니다. 데이터 소스 요청 1회로 계산됩니다."),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:"#%ED%85%8C%EC%9D%B4%EB%B8%94"},"테이블")," 참고")),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")," (타임스탬프, ms)"),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")," (타임스탬프, ms)"),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},"캔들")),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},"두 시리즈 사이를 채운 밴드, 각 캔들은 자체 색상과 불투명도를 가집니다")),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},"보이는 캔들에 대한 볼륨 프로파일 형태의 히스토그램, ",Object(b.b)("a",{parentName:"td",href:"#%ED%94%84%EB%A1%9C%ED%95%84"},"프로필")," 참고")),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:"#%ED%9E%88%EC%8A%A4%ED%86%A0%EA%B7%B8%EB%9E%A8"},"히스토그램")," 참고")))),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},"캔들당 하나의 값, ",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"},"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},"색상, 또는 캔들의 색상을 반환하는 함수: ",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")," = 캔들당 하나의 열(기본값), ",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// 각 캔들이 자체 색상을 가집니다: 종가가 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// 캔들별로 색칠된 영역, 큰 캔들일수록 더 불투명하게\nplot.areaSeries("Delta", deltas, (v, i) => v >= 0 ? colorBuy : colorSell, (v, i) => Math.min(1, Math.abs(v) / maxDelta));\n\n// 종가와 그보다 1% 아래 사이의 압력 밴드, 캔들의 불균형 비율에 따라 색상과 음영을 적용\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"),"에 대한 가격 맵입니다: ",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"),"를 그대로 전달할 수 있습니다), 행이 없는 캔들은 ",Object(b.b)("inlineCode",{parentName:"p"},"null"),". ",Object(b.b)("strong",{parentName:"p"},"차트에 보이는")," 캔들의 행은 차트 자체에서 가격 단위별로 합산되므로, 프로필은 새로 실행하지 않아도 이동, 확대/축소, 추가 로드를 따라갑니다. 단일 값은 한 가지 색상으로 그려지고(음수 값은 ",Object(b.b)("inlineCode",{parentName:"p"},"fill2"),"로), 쌍은 막대를 매수와 매도 부분으로 나누며 델타 모드를 사용할 수 있습니다. ",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"),"개, 캔들당 ",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// 대량 거래만, 델타 색상, 왼쪽 가장자리\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"},"차트 전체에 대한 하나의 가격 맵"),"이며, 캔들에서 합산되는 것은 없습니다. 행이 캔들에 속하고 그림이 보이는 범위를 따라가야 할 때는 ",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()"),"의 캔들 항목과 같은 형식을 가집니다: ",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"),"로), 쌍은 막대를 매수와 매도 부분으로 나누며 델타 모드를 사용할 수 있습니다. 옵션은 ",Object(b.b)("inlineCode",{parentName:"p"},"profile()"),"과 같으며, 위의 표를 참고하세요."),Object(b.b)("p",null,"히스토그램은 실행의 마지막 캔들 날짜를 가지며, 차트는 제목별로 ",Object(b.b)("strong",{parentName:"p"},"가장 최신")," 히스토그램을 유지하므로 오래된 캔들에 대한 부분 실행(히스토리 로딩)이 현재 히스토그램을 대체하지 않습니다. 스크립트가 새로고침될 때마다 다시 그려지므로, 오더북 히스토그램은 실시간 오더북을 따라갑니다. ",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개 캔들의 클러스터 거래량, 최근 캔들일수록 가중치가 큼\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 }"),"입니다. 같은 모서리의 테이블은 순서대로 쌓입니다. 테이블은 실행의 마지막 캔들 날짜를 가지며, 차트는 제목별로 ",Object(b.b)("strong",{parentName:"p"},"가장 최신")," 테이블을 유지하므로 오래된 캔들에 대한 부분 실행(히스토리 로딩)이 현재 테이블을 대체하지 않습니다. 너비가 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은 바 단위로 동작하지만, 여기서는 모든 함수가 전체 시리즈(배열, 캔들당 하나의 값, 오래된 것부터)를 받아 바로 플로팅할 수 있는 같은 길이의 시리즈를 반환합니다. 기간이 아직 채워지지 않은 동안 값은 ",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"),"개 바 동안의 최고값 / 최저값")),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},"최고 / 최저 바까지의 오프셋(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},"각 바까지의 역대 최고 / 최저값")),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"),"(불리언 배열)이 마지막으로 참이었던 이후의 바 수")),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},"확인 바에서의 피벗 값, 피벗 자체는 ",Object(b.b)("inlineCode",{parentName:"td"},"rightbars"),"개 바 이전에 있습니다")))),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},"와일더 이동평균(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},"헐 이동평균")),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},"아르노 르구 이동평균(ALMA)")),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개 바에 대한 대칭 가중 이동평균")),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},"상대강도지수(RSI)")),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},"무게 중심(Center of Gravity)")),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},"진정 강도 지수(TSI), -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},"실제 범위(True Range, ",Object(b.b)("inlineCode",{parentName:"td"},"handleNa = true"),"이면 첫 번째 바에서 ",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},"평균 실제 범위(ATR)")),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},"평균 방향성 지수(ADX)")),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"),"(불리언 배열)가 참인 바에서 다시 시작")),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},"온밸런스 볼륨(OBV)")),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},"매집 / 분산(A/D)")),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},"일중 강도 지수(Intraday Intensity Index)")),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},"가격-거래량 추세(PVT)")),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"},"웹훅 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"),"는 신호가 속한 캔들의 ",Object(b.b)("inlineCode",{parentName:"li"},"startTime"),"입니다. 같은 제목은 ",Object(b.b)("strong",{parentName:"li"},"더 새로운")," 캔들에 대해 발생할 때만 다시 알립니다. 사용자가 알림을 만든 시점보다 오래된 캔들의 신호는 무시됩니다(스팸 방지).")),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"),"로 자동 발생하므로 추가 코드 없이 스팸 방지 로직이 동작합니다. 캔들별 신호에는 이 방법을 권장합니다."),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"},"최신 데이터 포인트"),"와 최신 캔들 날짜를 받으며, 알림은 그 날짜로 발생합니다."),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")," — 콜백은 마지막 캔들 ",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"},"새 캔들"),"마다 한 번 알립니다. 일회성 신호에는 교차 방식의 조건(",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 캔들 가져오기\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 캔들 가져오기\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// 각 캔들의 오더북: depths()[i]는 candles[i]의 스냅샷(가장 큰 지정가 주문), 최신 캔들은 실시간 오더북을 사용\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 // 매수 압력: 매수가 최소 비율보다 더 우세한 캔들에서만 밴드를 채움\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 // 최신 캔들에 대한 알림\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/ko/Scripting.mdx"}}),m.isMDXComponent=!0}}]); //# sourceMappingURL=component---src-components-ko-scripting-mdx-df7107832c8bdd5ee494.js.map