decker
Deterministic market-state engine for trading agents — state, gate, coordinates, with receipts.
Should I use this
Quality & Safety
Findings (16)
- HIGH
- MEDIUMin decker.place_order
- LOWin decker.get_assembly
- LOWin decker.get_market_state
- LOWin decker.get_view
- LOWin decker.get_reading
- LOWin decker.get_signals
- LOWin decker.get_episodes
- LOWin decker.get_trigger_history
- LOWin decker.get_positions
Based on automated analysis of tool definitions and protocol compliance.
Context Cost
This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.
Install
One-Click Install
Add this to your `claude_desktop_config.json` file:
{
"mcpServers": {
"decker": {
"url": "https://api.decker-ai.com/api/v1/mcp"
}
}
}Remote endpoints
https://api.decker-ai.com/api/v1/mcpstreamable-httpWhat it can do
Tool inventory
Tools (14)
🟡decker.get_assembly(symbol, detail)
THE answer for 'what is the situation and what do I do on this symbol now' — one verdict per symbol, built from the per-timeframe judgment state (CR1); no scores or weights. READ IN THIS ORDER: (1) verdict = state (direction · phase) + action: 진입 enter now (a new signal) | 유지 hold the existing stance, NOT a new entry | 청산 exit | 대기 wait; `reason` says why, `until` names the close that would change it. (2) summary_ko = ready-to-show Korean lines. (3) entry / stop / target / rr = the prices (entry.mode says whether it is a new entry or on hold — when the action is not 진입 it never says 'now'; target may be null with target.reason, e.g. no coordinate at least 2% from the entry price; rr mixes the entry timeframe's stop with the target timeframe's target). (4) as_of = the bar this answer is based on. Default = the answer only (about 3KB per symbol; summary_ko already narrates the next closes and the last signal). Pass detail=true for the structured detail: path (nearby prices and what a close there means), watch (upcoming bar closes in time order and the question each decides), story (this / last signal), ladders, matrix_summary (every timeframe's row incl. gate), tf_states (EVERY timeframe's own state: judgment stage, open reversal test with its confirm price, engine action, next-bar label chain, recently missed targets — none folded by direction), knots (every timeframe's decision prices ordered by distance from the price, up and down, with which timeframes and roles sit on each — the ORDER in which transactions would be reached, not a probability). `reason` may end with '반대 방향 반전 보류 중: …' = other timeframes whose reversal test runs AGAINST the verdict's direction, i.e. is testing the current stance (a fact, not a vote; it never changes the action). Omit `symbol` for all 14 symbols. Roles: frame = highest confirmed timeframe (sets direction and target); entry = lowest aligned timeframe whose signal is alive; 1w supplies direction/target only, never an entry. grade: 정렬 aligned | 되돌림 pullback against the frame | 전환 시험 frame under test | 재장전 no confirmed signal. Caveats: 정렬 does not mean every timeframe's gate is GO (check matrix_summary[].gate); entry.mode '지금' does not mean a new event this bar. Narrate or filter the result — do not re-decide coordinates.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Optional symbol or alias (BTC, 비트코인, GOLD, 테슬라...). Omit for all 14 symbols."
},
"detail": {
"type": "boolean",
"description": "Include path / watch / story / ladders / matrix_summary (about 20KB per symbol). Default false: the answer only."
}
}
}🟢decker.get_market_state(symbol, timeframes, timeframe, events_limit)
PER-TIMEFRAME judgment state of a symbol, structured (consumer contract CR1) — the evidence behind decker.get_assembly's single verdict. For 'what is the situation and what do I do' call decker.get_assembly first; use this when you need one timeframe's exact state. Per timeframe (top→short): stage = target_selected (대상선정) | pending (판정보류: the close is still inside the signal bar) | confirmed (확인) | failed (실패) | none; side = buy/sell (a failed signal asserts nothing about the opposite side); signal_time; signal_bar {time, low, high} (its edges decide confirm/fail); entry (= close at the signal); stop; target (take-profit: opposite-side confirmed-signal edge at least 2% from entry, else null + target_reason); unit_target (the price this timeframe is judging now — NOT the take-profit); units (the targets judged together, max 6, primary first); reverse_pending (a reversal on hold: the first reversing key appeared, the next judgment bar has not closed beyond the target); standing (the last confirmed signal's entry/stop/target while a new target is being selected); prev_signal; turn (reverse|same|null); levels (nearby prices). state_text = ready-to-show Korean lines (🟢▲ buy confirmed · 🔴▼ sell confirmed · ⚪ pending · 🟡 target selected / reversal on hold · ✖️ failed). timeframe_summary lists timeframes by (stage, side) — a listing, not a verdict; no scores, weights or probabilities anywhere. events = recent target_selected / signal / signal_resolved / reverse_failed / reverse_tested / conn_arrival, newest first, always including each timeframe's own latest 2 (pass `timeframe` for one timeframe's full history). as_of = the latest closed bar among the returned timeframes (it can be earlier than get_assembly.as_of, which is the 30m bar). Read as persisted (no recompute). A state reading, NOT a trade instruction. Crypto and Hyperliquid synthetics only (KRX: decker.get_reading). Before placing any order, check the intent with decker.validate_intent.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT, XYZ_GOLDUSD"
},
"timeframes": {
"type": "array",
"items": {
"type": "string",
"enum": [
"30m",
"1h",
"4h",
"8h",
"1d",
"1w"
]
},
"description": "Subset to return. Omit for all timeframes."
},
"timeframe": {
"type": "string",
"enum": [
"30m",
"1h",
"4h",
"8h",
"1d",
"1w"
],
"description": "Alias for a single-element `timeframes` (backward compatible)."
},
"events_limit": {
"type": "integer",
"minimum": 0,
"maximum": 50,
"default": 10
}
},
"required": [
"symbol"
]
}Output Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string"
},
"as_of": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "가장 최근 평가 봉의 마감 시각"
},
"price": {
"type": [
"number",
"null"
],
"description": "가장 최근 평가 봉의 종가"
},
"state_text": {
"type": [
"string",
"null"
],
"description": "사용자에게 그대로 보여 줄 수 있는 현재 상태 문면 — 상위·중간·단기로 묶어 시간대마다 방향+단계, 마지막에 주목 가격. 해석·전망 문장은 없다(그건 호출자 몫). 시간대 행이 없으면 null"
},
"ladder": {
"type": "object",
"properties": {
"up": {
"type": "array",
"items": {
"type": "object",
"properties": {
"price": {
"type": "number"
},
"distance_pct": {
"type": "number"
},
"at": {
"type": "array",
"items": {
"type": "object",
"properties": {
"timeframe": {
"type": "string",
"enum": [
"1w",
"1d",
"8h",
"4h",
"1h",
"30m"
]
},
"kind": {
"type": "string",
"enum": [
"unit_target",
"next_unit_target",
"connection",
"candidate",
"signal_edge",
"decision"
]
},
"edge": {
"type": [
"string",
"null"
],
"enum": [
"confirm",
"fail",
null
]
},
"reads": {
"type": "string"
}
}
}
}
}
}
},
"down": {
"type": "array",
"items": {
"type": "object",
"properties": {
"price": {
"type": "number"
},
"distance_pct": {
"type": "number"
},
"at": {
"type": "array",
"items": {
"type": "object",
"properties": {
"timeframe": {
"type": "string",
"enum": [
"1w",
"1d",
"8h",
"4h",
"1h",
"30m"
]
},
"kind": {
"type": "string",
"enum": [
"unit_target",
"next_unit_target",
"connection",
"candidate",
"signal_edge",
"decision"
]
},
"edge": {
"type": [
"string",
"null"
],
"enum": [
"confirm",
"fail",
null
]
},
"reads": {
"type": "string"
}
}
}
}
}
}
}
},
"description": "현재가 위·아래 가까운 순서로 각 8개. 같은 가격은 한 점이고 at 에 그 가격이 어느 시간대에서 어떤 역할인지(kind) 모두 나열된다 — 하위 시간대가 닿는 가격이 상위 시간대의 대상·후보·신호봉 경계이면 그 한 사건이 두 시간대의 사건이다(상위는 하위의 조각이 모여 만들어진다). signal_edge.edge: confirm=그 방향 확인 경계 · fail=반대(실패) 경계. reads=그 칸의 사건 문장(역할→사건 표) + 그 시간대의 다음 마감 시각(판정은 종가). 우세·점수 없음"
},
"timeframe_summary": {
"type": "object",
"properties": {
"confirmed": {
"type": "object",
"properties": {
"buy": {
"type": "array",
"items": {
"type": "string"
}
},
"sell": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"pending": {
"type": "object",
"properties": {
"buy": {
"type": "array",
"items": {
"type": "string"
}
},
"sell": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"failed": {
"type": "object",
"properties": {
"buy": {
"type": "array",
"items": {
"type": "string"
}
},
"sell": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"target_selected": {
"type": "array",
"items": {
"type": "string"
}
}
},
"description": "시간대 행을 단계(confirmed 확인·pending 판정보류·failed 실패)와 방향(buy·sell)별로 나열만 한다. 우세·점수·투표 없음 — 실패는 반대 방향을 뜻하지 않는다. target_selected = 대상선정 중인 시간대 목록"
},
"timeframes": {
"type": "array",
"description": "상위→단기 순. 각 시간대가 낸 상태를 나란히 — 시간대 간 종합 판정은 없다(종합은 호출자 몫).",
"items": {
"type": "object",
"required": [
"timeframe",
"stage",
"side"
],
"properties": {
"timeframe": {
"type": "string",
"enum": [
"1w",
"1d",
"8h",
"4h",
"1h",
"30m"
]
},
"bar_close_time": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "이 시간대의 마지막 평가 봉 마감 시각"
},
"next_close_time": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "이 시간대의 진행 중인 봉이 닫히는 시각(마지막 평가 봉 마감 + 시간대 길이). 상위 봉은 하위 봉들이 모여 닫힌다"
},
"closes_with": {
"type": "array",
"items": {
"type": "string",
"enum": [
"1w",
"1d",
"8h",
"4h",
"1h",
"30m"
]
},
"description": "진행 중인 봉이 이 시간대와 같은 시각에 닫히는 다른 시간대 목록 — 겹치는 하위 봉의 종가가 상위 판정의 결정적 순간이다"
},
"close": {
"type": [
"number",
"null"
],
"description": "그 봉 종가"
},
"stage": {
"type": "string",
"enum": [
"target_selected",
"pending",
"confirmed",
"failed",
"none"
],
"description": "target_selected=대상선정 · pending=판정보류 · confirmed=확인 · failed=실패 · none=신호 없음. failed = that signal's judgment broke (the close crossed the signal bar's opposite edge) — it does NOT assert the opposite direction; read the timeframe's own fields (signal_bar / resolved_close / confirmed_at) for which price decided it."
},
"side": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
],
"description": "buy=매수 · sell=매도"
},
"signal_time": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "신호 시각(판단봉 2를 봉인하는 S 봉)"
},
"signal_bar": {
"type": [
"object",
"null"
],
"properties": {
"time": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"low": {
"type": [
"number",
"null"
]
},
"high": {
"type": [
"number",
"null"
]
}
},
"description": "신호봉(판단봉 2) — 종가가 이 범위 밖으로 나가면 확인/실패, 안이면 판정보류"
},
"confirmed_at": {
"type": [
"string",
"null"
],
"format": "date-time",
"description": "결말(확인/실패)이 난 봉 시각"
},
"resolved_close": {
"type": [
"number",
"null"
],
"description": "결말을 정한 종가"
},
"signal_position": {
"type": [
"string",
"null"
],
"enum": [
"for",
"against",
"inside",
null
],
"description": "확인·실패 신호의 지금 종가가 신호봉 대비 어디인가(신호 방향 반영) — for=신호 방향 경계 밖 · against=반대 경계 밖(불리; 신호 결과 stage 는 첫 결말로 고정이고 이후 이탈은 위치로만 남는다) · inside=신호봉 안"
},
"entry": {
"type": [
"number",
"null"
],
"description": "체결 기준 가격 = 신호 시점 종가"
},
"stop": {
"type": [
"number",
"null"
]
},
"target": {
"type": [
"number",
"null"
],
"description": "**목표가** — 진입가 대비 2% 이상 거리의 반대 측 확인 신호 경계(신호 이후 청산 좌표). 없으면 null. 판정 중인 대상 가격은 unit_target"
},
"target_reason": {
"type": [
"string",
"null"
],
"description": "target 이 null 인 이유"
},
"target_source_tf": {
"type": [
"string",
"null"
],
"enum": [
"1w",
"1d",
"8h",
"4h",
"1h",
null
],
"description": "목표가 **상위 시간대**의 확인된 반대 신호 경계(연계 좌표, 규칙표 R20.5·C4)일 때 그 시간대(예: '1w'). 자기 시간대 좌표면 null. 거리는 진입가 대비 단계 규칙 그대로이며 상위 시간대 좌표라 멀 수 있다"
},
"target_rr": {
"type": [
"number",
"null"
],
"description": "확인된 목표 좌표(target)가 없는 자리(신고점·신저점)에서 **손익비 2:1 기계값**. 새 상수 없이 손절 거리의 2배에서 파생되며 자동주문의 목표와 같은 값이다. 좌표가 아니라 계산값이므로 target 과 섞이지 않는다. target 이 있으면 null"
},
"unit_target": {
"type": [
"number",
"null"
],
"description": "이 시간대가 지금 판정 중인 **대상**(대상 가격, 앵커 C). 신호 이후 청산 좌표인 **목표가(target)와 다르다**"
},
"unit_target_touch": {
"type": [
"string",
"null"
],
"enum": [
"break",
"inside",
null
]
},
"units": {
"type": "array",
"items": {
"type": "object",
"properties": {
"unit_target": {
"type": "number"
},
"zone": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
]
},
"stage": {
"type": "string",
"enum": [
"target_selected",
"reverse_pending",
"confirmed",
"reverse_failed"
]
},
"primary": {
"type": "boolean"
},
"touch_kind": {
"type": [
"string",
"null"
],
"enum": [
"break",
"inside",
null
]
},
"touched_at": {
"type": [
"string",
"null"
]
},
"holds": {
"type": "integer"
},
"reverse_side": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
]
}
}
},
"description": "이 시간대가 **함께 보고 있는 대상 목록**(최대 6, 1순위 먼저). 한 시간대에서 대상은 하나가 아니다 — 1순위가 판정 중이어도 이전부터 있던 다른 대상이 터치되면 보조 유닛으로 각자 판정한다(수평·수직). unit_target = 그 대상 가격 · zone = 대상 자리(buy = 아래서 산 자리 · sell = 위에서 판 자리) · stage = target_selected 대상선정 | reverse_pending 반전 보류(테스트·보류 포함) | confirmed 확정 | reverse_failed 추세 변경 안 됨 · primary = 1순위 여부 · touch_kind = 터치 종류(break 종가로 돌파 · inside 꼬리만) · touched_at = 터치 봉 시각 · holds = 보류 이월 횟수 · reverse_side = 반전 측. 신호·결말(stage 최상위)과 별개 층이고 신호 아님."
},
"reverse_pending": {
"type": [
"object",
"null"
],
"properties": {
"side": {
"type": "string",
"enum": [
"buy",
"sell"
],
"description": "buy=매수 · sell=매도 (반전 측)"
},
"holds": {
"type": "integer",
"description": "보류를 넘긴 횟수(0 = 첫 시험 직후)"
},
"confirm": {
"type": [
"object",
"null"
],
"properties": {
"progress_price": {
"type": "number"
},
"unit_target_price": {
"type": "number"
},
"side_of_price": {
"type": "string",
"enum": [
"above",
"below"
]
}
}
},
"fail_side": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
]
},
"unit_target": {
"type": "number"
}
},
"description": "이 시간대가 지금 판정 중인 **반전**이 보류 상태일 때만 있다(그 외 null). side = 반전 측(대상 쪽의 반대: 대상이 매수 자리면 sell) · unit_target = 그 대상(기준 가격) · holds = 보류를 넘긴 횟수(0 = 첫 시험 직후) · confirm = 반전이 확인되려면 다음 판단봉이 progress_price 보다 side_of_price 쪽으로 진전하고 대상(unit_target_price)을 넘어 마감해야 한다 · fail_side = 이 측의 키가 나오면 반전 실패(대상이 방어됨, 진행 유지). 신호(stage)와 별개 — 직전 신호가 확인이어도 새 대상의 반전이 보류일 수 있다."
},
"action_switch": {
"type": [
"object",
"null"
],
"properties": {
"need": {
"type": "string",
"enum": [
"required",
"exit",
"pending",
"not_required"
]
},
"side": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
]
},
"stance": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
]
},
"unit_target": {
"type": [
"number",
"null"
]
},
"close_vs_target": {
"type": [
"string",
"null"
],
"enum": [
"above",
"below",
"at",
null
]
},
"mismatch": {
"type": "boolean"
},
"exit_edge": {
"type": [
"number",
"null"
]
},
"reversal_tests": {
"type": "object",
"properties": {
"buy": {
"type": "integer"
},
"sell": {
"type": "integer"
}
}
}
},
"description": "이 시간대 루프의 현재 위치가 사용자에게 주는 **행동전환 결정**(저자 10-11 교정 #9·#10: 런타임은 스냅샷이라 모든 상태가 결정을 낸다). need = required 전환 필요(이 봉에서 신호 확정, side 로 진입·반대 측이면 청산 후 리버스) · exit 청산(이 봉에서 직전 신호 실패 — stance 측 판단 근거 붕괴) · pending 전환 대기(확정 전, 반전 가설이 시험 중 — side = 후보 방향, 가설이 양방향이면 null) · not_required 전환 불필요(stance = 직전 신호 측 유지, 없으면 행동 없음). exit_edge = need=exit 를 정한 사건이 '확인된 신호의 신호봉 반대 경계 종가 이탈'일 때 그 경계 가격(매수=저가·매도=고가) — 표면이 경계를 추정하지 않도록 엔진이 싣는다, 다른 사건이 정한 행동이면 null · reversal_tests = 살아 있는 반전 가설 수(1순위+보조 유닛, 방향별 — 순위·승격 없음) · mismatch = 최근 키와 종가 위상이 엇갈림(양방향 동시 테스트) · close_vs_target = 1순위 대상 가격 대비 종가 위치. 신호(stage)·반전 보류와 별개 층이고 엔진 한 곳에서만 나온다. 가설도 신호도 없으면 null."
},
"label_next": {
"type": [
"object",
"null"
],
"properties": {
"state": {
"type": [
"string",
"null"
]
},
"hi": {
"type": [
"number",
"null"
]
},
"lo": {
"type": [
"number",
"null"
]
},
"next": {
"type": "object",
"properties": {
"F": {
"type": [
"string",
"null"
]
},
"B": {
"type": [
"string",
"null"
]
},
"I": {
"type": [
"string",
"null"
]
},
"W": {
"type": [
"string",
"null"
]
}
}
}
},
"description": "1순위 대상의 라벨이 **다음 한 봉**에 어떻게 되는지의 읽기. state = 지금 라벨 위치 · hi/lo = 직전 봉의 고가·저가(다음 봉이 이 두 가격에 대해 고가 갱신 F · 저가 갱신 B · 둘 다 아님 I · 둘 다 W 로 갈린다 — 종가가 아니다) · next = 움직임별 다음 라벨. 판정 입력이 아니라 읽기. 엔진이 아직 내지 않은 세대는 null."
},
"missed": {
"type": "array",
"items": {
"type": "object",
"properties": {
"time": {
"type": [
"string",
"null"
]
},
"price": {
"type": "number"
},
"sign": {
"type": [
"string",
"null"
]
},
"position": {
"type": [
"string",
"null"
],
"enum": [
"above",
"below",
"at",
null
]
},
"judging": {
"type": [
"number",
"null"
]
}
}
},
"description": "판정 없이 지나간 break(미싱)의 최근 몇 건(최신 먼저). 판정 중인 1순위가 있는 동안 태어난 대상이 터치브레이크되면 판정 대상이 아니라 미싱으로 남는다 — **상태**일 뿐 스윙 반전이 아니다. time = 그 봉 시각 · price = 그 대상 가격 · sign = 대상 부호 · position = 그 봉 종가가 대상의 위(above)/아래(below) · judging = 그때 판정 중이던 1순위 대상 가격."
},
"prev_signal": {
"type": [
"object",
"null"
],
"properties": {
"side": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
],
"description": "buy=매수 · sell=매도"
},
"stage": {
"type": "string",
"enum": [
"target_selected",
"pending",
"confirmed",
"failed",
"none"
],
"description": "target_selected=대상선정 · pending=판정보류 · confirmed=확인 · failed=실패 · none=신호 없음. failed = that signal's judgment broke (the close crossed the signal bar's opposite edge) — it does NOT assert the opposite direction; read the timeframe's own fields (signal_bar / resolved_close / confirmed_at) for which price decided it."
},
"signal_time": {
"type": [
"string",
"null"
],
"format": "date-time"
}
}
},
"standing": {
"type": [
"object",
"null"
],
"properties": {
"side": {
"type": "string",
"enum": [
"buy",
"sell"
]
},
"signal_time": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"entry": {
"type": [
"number",
"null"
]
},
"stop": {
"type": [
"number",
"null"
]
},
"target": {
"type": [
"number",
"null"
]
},
"target_rr": {
"type": [
"number",
"null"
]
}
},
"description": "**유지 중인 입장의 기준 신호**(단계가 대상선정일 때만, 직전 신호가 확인이고 아직 실패하지 않았을 때). 새 대상이 선정되어도 직전 확인 신호의 입장은 유지된다(action_switch.stance) — 그 입장의 진입가·손절·목표를 신호 단계 필드(entry·stop·target)와 섞지 않고 따로 싣는다. side = 유지되는 입장 · signal_time = 그 신호 시각 · entry = 체결 기준(신호 시점 종가) · stop = 손절 · target = 목표 좌표 · target_rr = 좌표가 없을 때 손익비 기계값. 신호 단계(pending·confirmed·failed)이거나 직전 확인 신호가 없으면 null"
},
"turn": {
"type": [
"string",
"null"
],
"enum": [
"reverse",
"same",
null
],
"description": "신호가 살아 있는 단계(pending·confirmed)에서 직전 신호와 방향이 바뀌면 reverse(기존 행동을 바꾸는 신호), 같으면 same(이어짐). 실패(failed)·신호 없음·직전 신호 없음은 null"
},
"levels": {
"type": [
"object",
"null"
],
"properties": {
"up": {
"type": "array",
"items": {
"type": "object"
}
},
"down": {
"type": "array",
"items": {
"type": "object"
}
}
},
"description": "주목 가격 — 종가 위·아래 가까운 가격 3개씩 {price, distance_pct, kind}. kind=unit_target(지금 판정 중인 대상 가격)|next_unit_target(다음 대상)|connection(과거 판정지점)|candidate(아직 닿지 않은 대상 후보). ⚠ 목표가(target)와 다른 말이다"
}
}
}
},
"events": {
"type": "array",
"description": "최근 사건(새것 먼저). 대상선정·신호·신호 결말·추세 변경 안 됨(reverse_failed: 1순위 대상의 반전이 실패한 판정 결과, side = 유지되는 추세 쪽 — 신호 아님)·반전 테스트(reverse_tested: 1순위 대상의 반전 첫 키 결과, status beyond|short — 신호 아님)·이전 판정 가격 도달(conn_arrival: 가격이 이전에 판정이 끝난 기준 가격에 닿음 — 방향·결말 판정 아님).",
"items": {
"type": "object",
"required": [
"time",
"timeframe",
"kind"
],
"properties": {
"time": {
"type": [
"string",
"null"
],
"format": "date-time"
},
"timeframe": {
"type": "string",
"enum": [
"1w",
"1d",
"8h",
"4h",
"1h",
"30m"
]
},
"kind": {
"type": "string",
"enum": [
"target_selected",
"signal",
"signal_resolved",
"conn_arrival",
"reverse_failed",
"reverse_tested"
],
"description": "conn_arrival(이전 판정 가격 도달) = 가격이 이전에 판정이 끝난 가격에 닿았다는 사실. 방향·결말 판정이 아니며 텔레그램으로는 보내지 않는다. reverse_failed(추세 변경 안 됨, 엔진 `judge_failed`) = 1순위 대상의 판정 결과 중 반전이 실패한 것 — side = 유지되는 추세 쪽, price = 그 대상. 신호가 아니라 판정 결과 사실이며(진입·청산 사용은 진입 모드 층의 몫, 게이트는 WATCH) 텔레그램 채널 없음. reverse_tested(반전 테스트, 엔진 `judge_test`) = 1순위 대상의 B 국면 첫 반대 키 결과 — side = 반전 쪽 키, price = 대상, status = beyond(테스트 S 종가가 대상 너머 = 최소 조건 충족)|short. 신호 아님·텔레그램 없음. 보조 유닛의 결과는 표면에 올리지 않는다."
},
"side": {
"type": [
"string",
"null"
],
"enum": [
"buy",
"sell",
null
],
"description": "buy=매수 · sell=매도"
},
"status": {
"type": [
"string",
"null"
],
"enum": [
"confirmed",
"failed",
"beyond",
"short",
null
],
"description": "signal_resolved 의 결말(confirmed|failed) · reverse_tested 의 최소 조건(beyond = 테스트 S 종가가 대상 너머 마감 · short = 못 넘음)"
},
"price": {
"type": [
"number",
"null"
],
"description": "signal/signal_resolved=종가 · 그 외=대상 가격"
}
}
}
},
"missing_timeframes": {
"type": "array",
"items": {
"type": "string"
},
"description": "아직 평가값이 없는 시간대"
}
},
"required": [
"symbol",
"as_of",
"price",
"timeframes",
"events",
"missing_timeframes"
]
}🟢decker.get_view(symbol, tf)
Ready-to-show Korean status card for a symbol — the same card the daily briefing sends, built from the same consumer contract (CR1) as decker.get_market_state, so direction and prices always agree with it. Shows the timeframes grouped 상위/중간/단기 with one line each (direction + stage + the price that decided it), the nearby prices to watch, and a short explanation of the chosen timeframe (tf, default 4h): what closed beyond what, whether the signal flips the previous one, entry/target/stop. Also returns direction (+/- only while that timeframe's signal is pending or confirmed; a failed or absent signal gives no direction — failure does not assert the opposite side), wait_target, invalidation, ref_price and recent self-scoring verdicts. Use this when you want text to show as-is; use decker.get_market_state when you want structured values to reason over. layer=STATE_VIEW: a market-state reading, NOT a trade instruction. Before placing any order through any execution tool, check the intent with decker.validate_intent.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT, XYZ_GOLDUSD (crypto + HL TradFi synthetics; KRX daily lineage not yet covered by view v1)"
},
"tf": {
"type": "string",
"enum": [
"30m",
"1h",
"4h",
"8h",
"1d"
],
"description": "Optional view timeframe — the grounded narrative is composed on this TF's bar (e.g. '1h' when the user asks about the 1-hour picture). Omit for the engine's default action TF (usually 4h, same as the daily briefing card)."
}
},
"required": [
"symbol"
]
}⚪decker.get_reading(symbol, tf, include_tfs)
How ONE timeframe looks right now, in plain language: state (phase, this timeframe's key direction, posture GO/WATCH/HOLD — a stance, not an order), mtf.by_tf (the same for other timeframes), narrative, plus `assembly` = the symbol's single verdict (the same one decker.get_assembly returns: direction, action 진입/유지/청산/대기, entry/stop/target). ⚠ `state.direction` is only this timeframe's direction and can differ from `assembly.direction` — for the decision use `assembly` (direction_basis says which is which). For the full detail call decker.get_assembly with detail=true; for the structured per-timeframe judgment use decker.get_market_state. Engine-native raw fields are not exposed here.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT"
},
"tf": {
"type": "string",
"enum": [
"15m",
"30m",
"1h",
"4h",
"8h",
"1d",
"1w"
],
"default": "4h"
},
"include_tfs": {
"type": "string",
"description": "Comma-separated additional TFs (e.g. '1h,4h,1d')."
}
},
"required": [
"symbol"
]
}🟢decker.get_signals(symbols, min_progress, action_gate, timeframe, limit)
Active trading signals for the current user (with Skill Overlay applied), in customer-facing shape: coordinates (entry/target/stop), decision (ENTER/WAIT/SKIP — is_actual_trigger=true only for ENTER; WAIT/SKIP are standing candidates, not executed triggers), action_gate posture (GO/WATCH/HOLD — a stance, not an order command), progress, MTF verdict, and a plain-language summary_ko line. risk_reward_ratio is computed on the DISPLAYED coordinates (after overlay). Signals are retained rather than cut when they age (turn-retention policy) — read freshness_state (open|aged) / age_bars / freshness_sec before treating an old PENDING row as current. Filtered by symbols / min_progress / action_gate — action_gate here filters the CURRENT-MOMENT representative state, it does not search history (almost always 0 rows unless a gate is GO right now); for past GO events with their entry/target/stop and realized performance use decker.get_trigger_history instead. Before placing any order through any execution tool, check the intent with decker.validate_intent.
Input Schema
{
"type": "object",
"properties": {
"symbols": {
"type": "array",
"items": {
"type": "string"
},
"description": "Symbol filter (e.g. ['BTCUSDT','ETHUSDT']). Omit for all."
},
"min_progress": {
"type": "number",
"minimum": 0,
"maximum": 100,
"description": "Minimum progress_pct (0-100)."
},
"action_gate": {
"type": "string",
"enum": [
"GO",
"WATCH",
"HOLD"
],
"description": "Engine action gate filter (3-layer grammar: gate = transition posture, not an order command). Rows where the engine emitted no gate for this bar (effective_action_gate null, e.g. KRX daily) are excluded when this filter is set."
},
"timeframe": {
"type": "string",
"enum": [
"30m",
"1h",
"4h",
"8h",
"1d"
],
"description": "Signal horizon filter (30m=scalp, 1h=swing, 4h/8h/1d=position). The same symbol can hold OPPOSITE directions on different horizons — omit to get the latest active signal regardless of horizon (its timeframe field says which one you got; when a specific symbols[] was requested, a row's other_horizon_conflict field flags it if another horizon is ACTIVE with the opposite direction). Prefer decker.get_assembly for the composed cross-horizon judgment instead of guessing which horizon to pass here."
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 20
}
}
}🟢decker.get_episodes(symbol, timeframe, limit)
Price-axis EPISODE history — answers 'where did I buy/sell last time, what was the target value and the event chain then, and where did price move WITHOUT a signal (and which target values it passed = missing points)'. Read-only from the persisted event ledger (no recompute). `episodes` (newest first) = one target selection until the next: target {price, from_price, reason}, chain (primary-unit judgment events), signals {ts, side, entry, targets, resolved{status, close, bar_low, bar_high}}, left (target_left: MISSING = a target value price passed through with no judgment; MOVED), missing, signal_gap (no signal in that episode), move {start_close, end_close, pct}. `signal_gaps` (ascending) = the interval between consecutive signals with its price move and the missing points inside (last one is open). Missing points carry `sign` and `position` (price below/above the target at the pass) — classify on the read side; do not re-decide coordinates. History starts at the first persisted event of this generation.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT"
},
"timeframe": {
"type": "string",
"enum": [
"30m",
"1h",
"4h",
"8h",
"1d",
"1w"
]
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 20,
"default": 5,
"description": "number of episodes"
}
},
"required": [
"symbol",
"timeframe"
]
}🟢decker.get_trigger_history(symbol, timeframe, since, limit)
ACTION axis — actual historical GO triggers (not standing WATCH/HOLD candidates) for a symbol, with entry/target/stop coordinates and realized performance (mfe_pct/mae_pct/exit_reason/exit_price from trigger_performance, null = still open). Distinct from decker.get_signals (which reflects only the current-moment state, not a searchable history — its action_gate filter answers 'what does symbol×tf look like right now', not 'when did this last fire'). Use this to answer 'what did the engine actually trigger recently and at what price' — decker.get_signals/get_market_state cannot answer that. direction is judgment_signals-native vocabulary ("long"/"short"), distinct from the "+"/"-" convention used by other tools — read as-is, no translation.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT"
},
"timeframe": {
"type": "string",
"enum": [
"30m",
"1h",
"4h",
"8h",
"1d"
],
"description": "Optional — omit for all timeframes."
},
"since": {
"type": "string",
"description": "ISO8601 lower bound on trigger time (exclusive). Optional."
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 50,
"default": 20
}
},
"required": [
"symbol"
]
}🟢decker.get_positions
Axis③ (Order/Execution) — this user's actual exposure (each open row carries vs_verdict: does the held side match the current symbol verdict, plus `knots` = the decision prices nearest to the price above and below, with which timeframes sit on each — the ORDER in which transactions would be reached, not a probability; `exit_levels` only when the held side matches): real open futures positions (execution_mode=real, with live sl_price/tp_price), virtual (paper) open positions, and the last 10 closed round-trips per mode. This is what your money actually did, distinct from decker.get_signals (axis②, what the engine recommends) — use this before deciding whether to place another order (avoid duplicate/over-exposure) and to check current protective stop/target on a real position.
Input Schema
{
"type": "object",
"properties": {}
}🟡decker.validate_intent(symbol, side, order_type, timeframe)
Pre-trade gate check for a proposed order intent. Call this BEFORE placing any order through any execution tool (e.g. a broker MCP's review→place flow). Checks the intent (symbol + side) against Decker's deterministic market state: engine action_gate (GO/WATCH/HOLD — a transition posture, not an order command), current structural state, and the active signal's direction / invalidation (stop) coordinates. Returns a stance reading, NOT an approval or rejection: the vocabulary is the engine gate as-is plus a mechanical tf_signal_alignment (aligned/opposed vs the active signal's direction). covered=false means the engine does not emit state for this symbol — treat as unknown, not as HOLD. top-level action_gate can be null even when covered=true — this is not a missing field, it means the current bar has no fresh trigger reading; check gate_null_reason ('no_gate_available' = neither the current bar nor the carried-forward signal had a gate at all, vs 'signal_stale' = a value existed but the underlying signal exceeded the staleness threshold and was deliberately suppressed rather than served as a confident-but-old answer). The order decision and responsibility remain with the calling agent/user. Every check is persisted to an auditable decision ledger (check_id). READ verdict_check FIRST: it compares the intent with the symbol's single verdict (the same one decker.get_assembly returns — direction, action 진입/유지/청산/대기, entry/stop/target, what would change it) and says in summary_ko whether a NEW entry exists now (entry_now) or the stance is only being held. The timeframe-level gate/signal fields below describe one timeframe (default: your open position's) and can be stale.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT, SILVER, 테슬라 — aliases resolve to the engine symbol (XYZ_SILVERUSD, XYZ_TSLAUSD, …)."
},
"side": {
"type": "string",
"enum": [
"buy",
"long",
"sell",
"short"
],
"description": "Proposed order direction (buy/long = +, sell/short = -)."
},
"order_type": {
"type": "string",
"description": "Optional, informational (market/limit/…) — recorded in the ledger, does not change the state verdict."
},
"timeframe": {
"type": "string",
"enum": [
"30m",
"1h",
"4h",
"8h",
"1d"
],
"description": "Gate horizon. Omit = your open position's entry TF if you hold one on this symbol, else decker.get_assembly's entry TF (the single judgment authority's current best-path TF), else the engine's default action TF (4h)."
}
},
"required": [
"symbol",
"side"
]
}⚪decker.get_user_skills
Trading skill catalog + currently active overlay for this user. Returns 8 published skills (conservative_v0/standard_v0/aggressive_v0/default_v0/scalp_v0/tight_v0/wide_v0/swing_v0) and the user's selected one. Also returns symbol_skills: the symbols where this user's paper account turns the symbol verdict's entry event into an order (read-only here; turn on/off via REST /auto-order-rules/symbol-skills).
Input Schema
{
"type": "object",
"properties": {}
}🟡decker.set_skill_overlay(skill_id)
Change active trading skill overlay for this user. Immediately affects all subsequent get_signals calls and downstream channels.
Input Schema
{
"type": "object",
"properties": {
"skill_id": {
"type": "string",
"description": "trading_skills.id (e.g. 'aggressive_v0')."
}
},
"required": [
"skill_id"
]
}🟢decker.place_order(symbol, side, notional_usd)
Axis③ (Order/Execution) — unlike every other tool here, this one moves money. It places a market order through DECKER'S OWN execution engine (same path as the decker-ai.com chat trading UI, source='mcp') — it does NOT hand off to your own broker connection or exchange account; Decker executes using whatever exchange credentials this user has separately linked to their Decker account on the website. execution_mode (virtual|real) is NOT chosen by the caller — it is resolved server-side from this user's account settings (user_settings.execution_mode) AND the platform's real-trading kill switch; a real-money order requires both an explicit user opt-in AND role/tier eligibility (PRO/ENTERPRISE or admin) AND passing the tier's hard notional/leverage/daily-count caps (checked here before dispatch — violation blocks the order, does not downgrade it to virtual). The response always states which mode actually executed — treat 'virtual' in the response as authoritative even if you expected real. Restricted to the crypto-6 universe (BTCUSDT/ETHUSDT/SOLUSDT/BNBUSDT/XRPUSDT/DOGEUSDT) for this MCP path — HL-synthetic and KRX symbols are read-only via other tools. Call decker.validate_intent first to read the engine's current stance; this tool does not check it for you. Positions are tracked as ONE net row per user+symbol+mode, not per order — if you already hold a position on this symbol, this order nets into it and the response's pre_existing_position field says so. A later close_position call closes the combined total, not just what this call added.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"enum": [
"BTCUSDT",
"ETHUSDT",
"SOLUSDT",
"BNBUSDT",
"XRPUSDT",
"DOGEUSDT"
],
"description": "Crypto-6 only for this MCP write path."
},
"side": {
"type": "string",
"enum": [
"buy",
"long",
"sell",
"short"
],
"description": "Order direction (buy/long or sell/short)."
},
"notional_usd": {
"type": "number",
"exclusiveMinimum": 0,
"description": "Order size in USD (quantity = notional_usd / current price). This is the value checked against the account's tier notional cap."
}
},
"required": [
"symbol",
"side",
"notional_usd"
]
}⚪decker.close_position(symbol, close_fraction)
Axis③ (Order/Execution) — closes (or partially reduces) an existing position through DECKER'S OWN execution engine (see decker.place_order for what that means — same account-linkage requirement applies here for real positions). Unlike place_order, there is no crypto-6 restriction — this reduces risk, not adds it, so any symbol you actually hold (including HL-synthetic/KRX paper positions) can be closed. Mode is NOT chosen by the caller — this looks up whatever position(s) actually exist for the symbol (real via live exchange query, virtual via the paper ledger) and closes whichever are open; if both a real and a virtual position exist for the same symbol, both are closed and the response reports execution_mode as 'mixed'. No open position for the symbol = a clean not-found response, not an error — safe to call speculatively.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT, XYZ_GOLDUSD — whatever symbol you hold. Aliases resolve like other tools."
},
"close_fraction": {
"type": "number",
"exclusiveMinimum": 0,
"maximum": 1,
"default": 1,
"description": "Fraction of the current position to close, 0 < x <= 1. Default 1.0 = full close. E.g. 0.5 closes half."
}
},
"required": [
"symbol"
]
}🔴decker.update_protective_stops(symbol, sl_price, tp_price, mode)
Axis③ (Order/Execution) — modifies the stop-loss and/or take-profit on an EXISTING open position. There is no cancel_order tool because Decker only places market orders (there is no resting order to cancel) — the actual gap this fills is modifying protective stops on a position you already hold. real: cancels the old exchange stop/take-profit order(s) and places new ones at the given price(s) (new order placed first, old one canceled only after — no unprotected window). virtual: updates the paper position's stop_loss/take_profit columns directly (polled by the paper monitor). Provide at least one of sl_price/tp_price — the other side, if omitted, is left at its current value. If both a real and a virtual position are open for this symbol, pass mode explicitly or the call is rejected asking which one.
Input Schema
{
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "e.g. BTCUSDT — must be a symbol you currently hold."
},
"sl_price": {
"type": "number",
"exclusiveMinimum": 0,
"description": "New stop-loss price. Omit to leave the current stop unchanged."
},
"tp_price": {
"type": "number",
"exclusiveMinimum": 0,
"description": "New take-profit price. Omit to leave the current target unchanged."
},
"mode": {
"type": "string",
"enum": [
"real",
"virtual"
],
"description": "Only required when both a real and a virtual position are open for this symbol — says which one to modify."
}
},
"required": [
"symbol"
]
}Community
Evidence