Daepak

김치 프리미엄 트레이딩뷰 인디케이터

김프를 하나의 숫자가 아니라 원화 다리자산 다리로 나눠서 그립니다. Pine Script 전체 코드를 아래에 공개했습니다 — 복사해서 붙여넣으면 끝이고, 계정도 결제도 필요 없습니다.

왜 한 숫자로는 부족한가

환율로 계산한 김프는 성격이 다른 두 가지를 섞어 놓은 값입니다. 둘은 자주 반대 방향으로 움직입니다.

구성무엇을 재는가특징
원화 다리국내 USDT가 시장 환율보다 얼마나 비싸거나 싼지 통화 쪽 값이라 모든 코인에 똑같이 적용됩니다
자산 다리통화 효과를 걷어낸 뒤 코인 자체에 남는 값 실제 국내 수요는 여기에 나타납니다

전체 프리미엄이 마이너스인데 자산 다리가 0에 가깝다면, 그 코인이 국내에서 싸게 팔리는 것이 아니라 원화 환전 쪽에서 생긴 값입니다. 전체 숫자만 보면 이 상황을 정반대로 읽게 됩니다. 인디케이터는 두 다리가 서로 다른 방향을 가리키는 구간을 붉게 칠해 그 지점을 바로 보여줍니다.

계산식

전체 프리미엄 = (국내가 ÷ USD/KRW) ÷ 해외가 − 1
원화 다리     = 국내 USDT ÷ USD/KRW − 1
자산 다리     = (1 + 전체) ÷ (1 + 원화 다리) − 1
자산 다리는 계산으로 유도합니다. 코인의 USDT 페어에서 직접 재지 않습니다. 2026년 7월 30일 저희 측정에서 업비트 두 호가창으로 역산한 환율은 BTC에서 1424(시장 1423)로 맞았지만 SOL 1449, DOGE 1451로 벌어졌습니다. 알트의 USDT 페어는 얇고 호가가 오래 서 있어서, 직접 잰 자산 다리는 측정이 아니라 잡음이었습니다. 유도한 값은 언제나 관측된 전체 프리미엄과 다시 맞아떨어집니다.

설치 방법 (2분)

  1. 트레이딩뷰 차트를 열고 하단 Pine 에디터를 펼칩니다.
  2. 아래 코드를 전부 복사해 에디터 내용을 덮어씁니다.
  3. 차트에 추가를 누릅니다. 기본값은 BTC 기준(업비트 · 바이낸스 · USD/KRW · 업비트 USDT)입니다.
  4. 다른 코인을 보려면 설정에서 Symbols 네 칸을 같은 코인으로 바꾸면 됩니다.

Pine Script 전체 코드

// Kimchi Premium — won leg vs asset leg
// by Daepak · https://daepak.com/kimchi · MIT
//
// The kimchi premium is usually published as one number: how much more expensive a coin is
// on a Korean exchange than abroad, converted at the FX rate. That single number mixes two
// different things, and they often move in opposite directions:
//
//   won leg    — how far Korean USDT trades from the market USD/KRW rate. It is a currency
//                effect and applies to every coin equally.
//   asset leg  — what is left for the coin itself once the currency effect is removed.
//
// If the total premium is negative but the asset leg is near zero, the coin is not cheap in
// Korea — the won conversion is. Reading the total alone gets that backwards.
//
// The asset leg is DERIVED as (1 + total) / (1 + won) − 1, not measured from the coin's own
// USDT pair on Upbit. We tested the direct measurement on 2026-07-30: the implied rate from
// two Upbit order books matched for BTC (1424 vs 1423 market) but drifted to 1449 for SOL
// and 1451 for DOGE, because altcoin USDT pairs are thin and go stale. The derived leg always
// adds back up to the observed total; the direct one was noise.
//
// Honest limit: in our own backtest of 646 episodes, neither leg predicted price direction
// over horizons up to 24 hours. The decomposition explains what is happening now. It does not
// forecast, and this script is not investment advice.

//@version=6
indicator("Kimchi Premium · won leg vs asset leg", "Kimchi legs", overlay = false, precision = 2)

// ───────────────── inputs ─────────────────
gS = "Symbols"
krSym   = input.symbol("UPBIT:BTCKRW",    "Korean market (KRW)",  group = gS,
     tooltip = "The coin on a Korean exchange, quoted in won. Change this to follow another coin.")
glSym   = input.symbol("BINANCE:BTCUSDT", "Global market (USD)",  group = gS,
     tooltip = "The same coin on a global exchange. Must be the same asset as the Korean symbol.")
fxSym   = input.symbol("FX_IDC:USDKRW",   "USD/KRW reference",    group = gS,
     tooltip = "The market exchange rate used to convert. This is the rate the premium is measured against.")
usdtSym = input.symbol("UPBIT:USDTKRW",   "Korean USDT (KRW)",    group = gS,
     tooltip = "USDT priced in won on a Korean exchange — the most liquid stablecoin market, used to measure the won leg.")

gV = "View"
showTotal = input.bool(true,  "Total premium (FX based)", group = gV)
showWon   = input.bool(true,  "Won leg",                  group = gV)
showAsset = input.bool(true,  "Asset leg",                group = gV)
showTable = input.bool(true,  "Value panel",              group = gV)

gA = "Alerts"
hiLevel = input.float(5.0,  "Alert above (asset leg, %)", group = gA, step = 0.5)
loLevel = input.float(-3.0, "Alert below (asset leg, %)", group = gA, step = 0.5)

// ───────────────── data ─────────────────
kr   = request.security(krSym,   timeframe.period, close)
gl   = request.security(glSym,   timeframe.period, close)
fx   = request.security(fxSym,   timeframe.period, close)
usdt = request.security(usdtSym, timeframe.period, close)

ok    = not na(kr) and not na(gl) and not na(fx) and gl > 0 and fx > 0
total = ok ? (kr / fx) / gl - 1.0 : na
won   = not na(usdt) and not na(fx) and fx > 0 ? usdt / fx - 1.0 : na
// derived, never taken from the coin's own USDT pair — see the header note
asset = not na(total) and not na(won) ? (1.0 + total) / (1.0 + won) - 1.0 : na

totalP = total * 100
wonP   = won   * 100
assetP = asset * 100

// ───────────────── plots ─────────────────
pT = plot(showTotal ? totalP : na, "Total premium", color = color.new(#7A5CFF, 0),  linewidth = 2)
pW = plot(showWon   ? wonP   : na, "Won leg",       color = color.new(#F79009, 0),  linewidth = 1)
pA = plot(showAsset ? assetP : na, "Asset leg",     color = color.new(#12B76A, 0),  linewidth = 2)
hline(0, "Parity", color = color.new(color.gray, 40), linestyle = hline.style_dashed)

// where the two legs disagree — the case the single number hides
fillCol = not na(wonP) and not na(assetP) and wonP * assetP < 0 ? color.new(#F04438, 88) : color.new(color.gray, 94)
fill(pW, pA, color = fillCol, title = "Gap between legs")

// ───────────────── panel ─────────────────
f_pct(float v) => na(v) ? "—" : (v > 0 ? "+" : "") + str.tostring(v, "#.##") + "%"

if showTable and barstate.islast
    var table t = table.new(position.top_right, 2, 5, border_width = 1)
    table.cell(t, 0, 0, "Kimchi premium",  text_color = color.white, bgcolor = #5B3DF5, text_size = size.small)
    table.cell(t, 1, 0, "now",             text_color = color.white, bgcolor = #5B3DF5, text_size = size.small)
    table.cell(t, 0, 1, "Total (FX based)", text_size = size.small)
    table.cell(t, 1, 1, f_pct(totalP), text_size = size.small,
     text_color = na(totalP) ? color.gray : totalP >= 0 ? #12B76A : #F04438)
    table.cell(t, 0, 2, "Won leg",     text_size = size.small)
    table.cell(t, 1, 2, f_pct(wonP),   text_size = size.small,
     text_color = na(wonP) ? color.gray : wonP >= 0 ? #12B76A : #F04438)
    table.cell(t, 0, 3, "Asset leg",   text_size = size.small)
    table.cell(t, 1, 3, f_pct(assetP), text_size = size.small,
     text_color = na(assetP) ? color.gray : assetP >= 0 ? #12B76A : #F04438)
    table.cell(t, 0, 4, na(assetP) ? "waiting for data" :
     math.abs(assetP) < 0.3 ? "currency effect, not the coin" :
     assetP > 0 ? "Korean demand for the coin" : "coin discounted in Korea",
     text_size = size.tiny, text_color = color.gray)
    table.cell(t, 1, 4, "daepak.com", text_size = size.tiny, text_color = color.gray)

// ───────────────── alerts ─────────────────
alertcondition(ta.crossover(assetP,  hiLevel), "Asset leg above level",
     "Kimchi asset leg crossed above the upper level")
alertcondition(ta.crossunder(assetP, loLevel), "Asset leg below level",
     "Kimchi asset leg crossed below the lower level")
alertcondition(ta.cross(wonP * assetP, 0),     "Legs diverged",
     "Kimchi legs now point in opposite directions — the single premium number is misleading here")

솔직한 한계

저희가 646개 구간으로 검증한 결과, 두 다리 모두 24시간 이내 가격 방향을 예측하지 못했습니다. 분해는 지금 무슨 일이 벌어지고 있는지 설명하는 도구이지 앞을 맞히는 도구가 아닙니다. 이 스크립트는 투자 자문이 아니며, 판단과 책임은 사용자에게 있습니다.

실시간 값과 더 깊은 분석

전체 마켓의 김프 순위, 원화 다리와 자산 다리의 실시간 값, 업비트 신규 상장의 첫 캔들부터의 기록은 김치 프리미엄 페이지에서 바로 볼 수 있습니다. 로그인 없이 열립니다. 같은 데이터를 API와 MCP로 부르려면 개발자 문서를 보세요 — ChatGPT나 Claude에서 바로 질문할 수도 있습니다(연결 방법).