跳到主要内容

开始使用

用自有图表构建宿主页面,再将 iC Candle 嵌入应用加载为 iframe。

步骤 1 — 挂载 iframe​

<iframe
id="iccandle"
src="https://embed-iccandle-app.iccandle.ai/zh?theme=light&header=false"
title="iC Candle"
allow="clipboard-write; payment"
style="width: 100%; height: 100%; border: 0;"
></iframe>

使用语言路径(/en、/zh 等)、可选的 theme(light | dark | system),以及在希望隐藏嵌入顶栏时使用的 header=false。

完整的扫描查询参数说明见 搜索参数。

不要用会阻止弹窗(Google / Cognito 登录)或顶层导航(Stripe Checkout)的方式 sandbox iframe。

步骤 2 — 发送父页面 origin(计费)​

在 iframe load 时告知嵌入端你的 origin,以便 Stripe 可返回到你的域名:

const EMBED_ORIGIN = "https://embed-iccandle-app.iccandle.ai";
const iframe = document.getElementById("iccandle");

iframe.addEventListener("load", () => {
iframe.contentWindow.postMessage(
{ type: "parent-origin", origin: window.location.origin },
EMBED_ORIGIN,
);

// Stripe 重定向回宿主 ?payment=success 之后:
if (new URLSearchParams(location.search).get("payment") === "success") {
iframe.contentWindow.postMessage({ type: "payment-success" }, EMBED_ORIGIN);
}
});

步骤 3 — 监听嵌入消息​

仅接受来自嵌入 origin 的消息。载荷可能是普通对象,也可能是 JSON 字符串,因此要先统一解析 event.data。

完整消息目录与载荷结构见 窗口消息 与 数据类型。

对于 iframe 宿主,当前嵌入协议主要使用带命名空间的包裹格式:

type EmbedMessage = {
name?: string;
data?: unknown;
type?: string;
pattern?: unknown;
};

大多数外发消息使用 name,例如 auth.signIn、selector.loading、chart.play、news.eventClicked、nav.click。

某些形态选择流程仍会直接发送对象而不是 name 包裹格式,因此宿主应同时检查 message.name 与 message.type。

共享类型​

/** OHLC K 线,与 cacheCandle 及回放载荷一致 */
interface Candle {
o: number; // open
h: number; // high
l: number; // low
c: number; // close
timestamp: number; // K 线时间,unix 秒
}

/** 日历 / 经济事件(新闻流程) */
interface NewsEvent {
id: string;
timestamp: number; // unix ms
event_name: string;
metric: string;
forecast: string;
actual: string;
previous: string;
currency: string;
}

处理器骨架​

window.addEventListener("message", (event) => {
if (event.origin !== EMBED_ORIGIN) return;

let message;
try {
message =
typeof event.data === "string" ? JSON.parse(event.data) : event.data;
} catch {
return;
}

switch (message?.name) {
case "auth.signIn":
localStorage.setItem("iccandle_token", message.data.idToken);
break;
case "selector.loading":
toggleHostLoading(message.data.isLoading);
break;
case "chart.play":
onChartReplay(message.data);
break;
case "chart.stop":
clearReplayAndOverlays();
break;
case "selector.closeResult":
clearReplayAndOverlays();
break;
case "nav.click":
onEmbedNav(message.data.href);
break;
case "news.eventClicked":
onNewsEvent(message.data.event, message.data.similarDetails);
break;
case "news.selectedEventPayloads":
persistSelectedNewsEvents(message.data);
break;
case "news.back":
case "news.backToSimilarEvents":
clearNewsReplayAndEventLine();
break;
case "news.iframeReady":
onEmbedReady();
break;
case "news.analyzeImpact":
onNewsAnalyzeImpact();
break;
case "pattern.classicPatternSelected":
drawPatternRange(message.data?.pattern);
break;
case "pattern.clearClassicPatternSelected":
clearPatternRange();
break;
case "pattern.custom_pattern_selected":
drawTrackedPatternRange(message.data?.pattern);
break;
case "pattern.clear_custom_pattern_selected":
clearTrackedPatternRange();
break;
}
});

name 消息(嵌入端 → 父页面)​

name触发时机载荷宿主动作
auth.signIniframe 内登录完成(邮箱密码或 OAuth){ name: "auth.signIn", data: { idToken: string } }将 data.idToken 存为 iccandle_token,供 Bearer API 调用
selector.loading扫描或 AI 准备开始 / 结束{ name: "selector.loading", data: { isLoading: boolean } }显示 / 隐藏图表或页面上的加载 UI
chart.play用户从新闻或图表分析流程启动回放{ name: "chart.play", data: { isReplay: true, predictCandles?: Candle[] | null, playEndTimestamp: number | null, selectedCandles: Candle[] | null } }注入回放 K 线 / 生成 K 线,并在 playEndTimestamp 前阻止实时 tick
chart.stop回放被清除或关闭{ name: "chart.stop", data: { isReplay: false, predictCandles?: Candle[] | null, playEndTimestamp: null, selectedCandles: null } } 或 { name: "chart.stop", data: null }清除回放 K 线与回放专属叠加
selector.closeResult用户关闭当前结果 / 分析面板{ name: "selector.closeResult", data: null }清除回放与结果专属叠加
nav.click用户点击嵌入端头部导航{ name: "nav.click", data: { href: string } }可选,响应标签或路由切换
news.eventClicked用户选中一个日历 / 经济事件{ name: "news.eventClicked", data: { event: NewsEvent, similarDetails: object | null } }将图表居中到事件位置,绘制竖线并高亮时间轴标记
news.selectedEventPayloads用户选择扫描器中的新闻事件{ name: "news.selectedEventPayloads", data: NewsEvent[] }若图表支持时间轴标记则持久化这些事件
news.back用户离开新闻详情或相似事件视图{ name: "news.back", data: null }清除事件竖线、标记与新闻回放叠加
news.backToSimilarEvents用户在新闻流程内返回{ name: "news.backToSimilarEvents", data: null }与 news.back 相同,清理事件专属图表装饰
news.iframeReady相似事件 iframe 完成初始加载{ name: "news.iframeReady", data: null }可选的宿主生命周期钩子
news.analyzeImpact用户请求新闻影响分析{ name: "news.analyzeImpact", data: null }可选,按需接入分析相关宿主 UI
pattern.classicPatternSelected用户选择一个经典 / 通用形态匹配{ name: "pattern.classicPatternSelected", data: { pattern: object } }高亮对比形态区间
pattern.clearClassicPatternSelected用户清除经典 / 通用形态选择{ name: "pattern.clearClassicPatternSelected", data: null }移除形态高亮
pattern.custom_pattern_selected用户选择一个追踪形态{ name: "pattern.custom_pattern_selected", data: { pattern: object } }高亮追踪形态区间
pattern.clear_custom_pattern_selected用户清除追踪形态选择{ name: "pattern.clear_custom_pattern_selected", data: null }移除追踪形态高亮

playEndTimestamp 使用 unix 秒。

pattern 对象来自扫描 / 形态追踪结果。宿主通常只需要其中的起止时间戳(或等价区间字段)来绘制高亮,可在浏览器开发者工具中查看一条实时消息后映射到你的图表 API。

步骤 4 — 认证​

应用路由需要会话。无 cookie 打开嵌入端会重定向到 /{locale}/sign-in。

  • 邮箱密码与 OAuth 在 iframe 内部完成(因提供方禁止被嵌,OAuth 使用弹窗)。
  • 成功后嵌入端发送 auth.signIn,载荷为 { data: { idToken } }。
  • 若宿主将调用 cacheCandle 或其他 API,请将该 token 存为 iccandle_token。

步骤 5 — 执行扫描​

5a — 缓存 K 线​

对所选窗口 POST https://scan-service.iccandle.ai/cacheCandle:

Authorization: Bearer <iccandle_token>
Content-Type: application/json

{
"candles": [
{ "o": 1.08, "h": 1.09, "l": 1.07, "c": 1.085, "timestamp": 1719878400 }
]
}
字段说明
o, h, l, c开 / 高 / 低 / 收
timestampUnix 秒(K 线时间)

响应包含 id — 用作 iframe URL 中的 cid。

5b — 导航 iframe​

const params = new URLSearchParams({
tk: "10", // top_k(默认 10)
symbol: "EURUSD",
res: "60", // 匹配周期
ref_res: "60", // 缓存窗口的参考周期
cid: candleId, // 来自 cacheCandle
from: String(startTimestampSec * 1000), // ms — 新闻区间辅助
to: String(endTimestampSec * 1000), // ms — 新闻区间辅助
theme: "light",
header: "false",
model: "light", // AI 结果模型:light | pro
temperature: "1", // AI 结果温度:0.5 | 1 | 1.5
});

// 可选:&fs=EURUSD,GBPUSD &period=<unixSec>
iframe.src = `${EMBED_ORIGIN}/zh?${params}`;

首页扫描必填:symbol、res、ref_res、cid。缺失时嵌入端会跳过 /search。

所有受支持的查询参数、默认值与按路由划分的说明见 搜索参数。

步骤 6 — 根据消息驱动图表​

消息宿主职责
chart.play / chart.stop在图表上注入或清除回放 K 线 / 生成 K 线
pattern.classicPatternSelected / pattern.custom_pattern_selected高亮对比形态区间
pattern.clearClassicPatternSelected / pattern.clear_custom_pattern_selected移除该区间
news.eventClicked / news.selectedEventPayloads / news.back新闻标记、竖线、选中事件状态与事件回放清理
nav.click可选,响应用户切换嵌入标签(data.href)。使用 header=false 时不会发出。

图表库由你掌控;嵌入端仅通过 postMessage 表达意图。

最小布局​

将图表与 iframe 并排(小屏可上下堆叠)。给 iframe 固定高度或 flex 子项,以便结果 UI 在框内滚动。

合作方嵌入时建议使用 header=false,让宿主导航保持主导,iframe 专注于扫描结果、形态追踪与新闻流程。

下一步​

参见 搜索参数 了解扫描 URL 合约,窗口消息 了解完整消息目录,数据类型 了解共享载荷,以及 API 参考 了解路由与协议细节。