#!/usr/bin/env python3 """Generate business-style XMind (Zen/2020+) from playbook + behavior rules.""" from __future__ import annotations import json import uuid import zipfile from pathlib import Path from typing import Any, Optional OUT = Path(__file__).resolve().parents[1] / "docs" / "交易执行手册与行为准则.xmind" # 商务配色:深蓝主调 + 灰蓝辅色 + 强调色 C_ROOT = "#0F2942" C_L1 = "#1B4F72" C_L2 = "#2E86AB" C_PASS = "#1E8449" C_FAIL = "#922B21" C_WARN = "#B9770E" C_MUTED = "#566573" C_TEXT = "#FFFFFF" C_TEXT_DARK = "#1C2833" def tid() -> str: return uuid.uuid4().hex[:26] def style( *, fill: Optional[str] = None, color: Optional[str] = None, font_size: str = "12pt", bold: bool = False, shape: str = "org.xmind.topicShape.roundedRect", line: Optional[str] = None, ) -> dict[str, Any]: props: dict[str, str] = { "shape-class": shape, "fo:font-family": "Microsoft YaHei", "fo:font-size": font_size, "fo:font-weight": "bold" if bold else "normal", "border-line-width": "0pt", "line-width": "1.5pt", "line-class": "org.xmind.branchConnection.roundedelbow", } if fill: props["svg:fill"] = fill if color: props["fo:color"] = color if line: props["line-color"] = line return {"id": tid(), "properties": props} def topic( title: str, children: list | None = None, *, markers: list[str] | None = None, labels: list[str] | None = None, notes: str | None = None, fill: Optional[str] = None, color: Optional[str] = None, font_size: str = "12pt", bold: bool = False, line: Optional[str] = None, ) -> dict: node: dict[str, Any] = { "id": tid(), "class": "topic", "title": title, "style": style( fill=fill, color=color, font_size=font_size, bold=bold, line=line ), } if markers: node["markers"] = [{"markerId": m} for m in markers] if labels: node["labels"] = labels if notes: node["notes"] = {"plain": {"content": notes}} if children: node["children"] = {"attached": children} return node def t1(title: str, children: list, markers: list[str], label: str) -> dict: return topic( title, children, markers=markers, labels=[label], fill=C_L1, color=C_TEXT, font_size="16pt", bold=True, line=C_L1, ) def t2(title: str, children: list | None = None, markers: list[str] | None = None) -> dict: return topic( title, children, markers=markers or ["flag-dark-blue"], fill=C_L2, color=C_TEXT, font_size="13pt", bold=True, line=C_L2, ) def leaf( title: str, *, markers: list[str] | None = None, fill: Optional[str] = None, color: Optional[str] = C_TEXT_DARK, ) -> dict: return topic( title, markers=markers or ["symbol-right"], fill=fill or "#EBF5FB", color=color, font_size="11pt", line="#AED6F1", ) def ok(title: str) -> dict: return leaf(title, markers=["other-yes", "symbol-right"], fill="#E8F8F5", color=C_PASS) def no(title: str) -> dict: return leaf(title, markers=["other-no", "flag-gray"], fill="#FDEDEC", color=C_FAIL) def warn(title: str) -> dict: return leaf(title, markers=["symbol-info"], fill="#FEF9E7", color=C_WARN) def build_content() -> list: root = topic( "交易执行体系\n手册 v2 · 开单三检", [ t1( "① 设计理念", [ t2( "核心主张", [ leaf("少而精,珍惜机会,样本干净", markers=["star-dark-blue"]), leaf("不保证收益;过程可控,结果随缘", markers=["symbol-info"]), leaf("过滤比频率重要;日更不是目标", markers=["symbol-info"]), leaf("看不懂不做;不为开单找理由", markers=["symbol-info"]), warn("丢掉对冲:无「有保护就能多做」幻觉"), ], markers=["other-lightbulb"], ), t2( "工具边界", [ leaf("OKX 期权:方向单(虚值等)", markers=["flag-blue"]), leaf("Gate 合约:结构清楚时的波段", markers=["flag-dark-blue"]), leaf("同一时段尽量只让一边说话", markers=["symbol-equality"]), no("不做期期对冲 / 偏置壳"), ], markers=["symbol-info"], ), t2( "文档分工", [ leaf("行为准则:能不能动手(防火墙)", markers=["other-lock"]), leaf("执行手册:怎么做单(玩法/仓位/离场)", markers=["other-note"]), ], markers=["other-businesscard"], ), ], markers=["priority-1", "other-lightbulb"], label="理念", ), t1( "② 资金要求", [ t2( "总盘约 800U", [ leaf("单笔约 1.25% 量级", markers=["symbol-info"]), leaf("全错一天约 2.5% 量级——防守优先", markers=["symbol-info"]), ], markers=["other-businesscard"], ), t2( "单笔期权", [ leaf("约 10U 权利金预算", markers=["priority-1"]), leaf("一次只持有一个期权仓位", markers=["symbol-info"]), leaf("打满 = min(余额, 单笔预算)", markers=["symbol-equality"]), ], markers=["flag-blue"], ), t2( "Gate 合约", [ leaf("日内保证金约 50U · 约 10 倍", markers=["symbol-info"]), leaf("止损一般约 5U", markers=["symbol-info"]), leaf("单笔最大亏损不超过约 10U", markers=["flag-gray"]), leaf("有单才用保证金,无单为 0", markers=["task-done"]), ], markers=["flag-dark-blue"], ), t2( "日损失心理框", [ warn("都错:合计大约 ≤20U"), ok("都对:期望可到 40U+(理想,非每日目标)"), no("不为「好像有保护」放大仓位"), warn("尽量少同向双开;双开按合计最坏约 20U"), ], markers=["symbol-info"], ), ], markers=["priority-2", "other-businesscard"], label="资金", ), t1( "③ 操盘思路", [ t2( "行为准则 · 开单三检", [ topic( "一句话防火墙", [ leaf("信号够不够清晰?", markers=["symbol-question"]), leaf("流程有没有跑通?", markers=["symbol-question"]), leaf("情绪是不是在证明自己?", markers=["symbol-question"]), no("三检不过 → 不开"), ], markers=["other-lock", "priority-1"], fill="#154360", color=C_TEXT, font_size="12pt", bold=True, labels=["防火墙"], ), topic( "总循环", [ leaf("信号判断 → 流程确认 → 情绪自检", markers=["arrow-right"]), leaf("全部通过 → 开仓", markers=["other-yes"]), leaf("等待系统结果(止盈/止损/到期)", markers=["other-clock"]), leaf("复盘整环 → 等待下一信号", markers=["arrow-refresh"]), no("任一步否决 → 空仓离开"), ], markers=["arrow-right"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, ), topic( "开单前三秒停顿", [ leaf("核心信号是什么?", markers=["symbol-info"]), leaf("安全流程跑通了吗?", markers=["task-start"]), leaf("冷静执行,还是怕踏空/回本/证明自己?", markers=["symbol-info"]), ], markers=["other-clock"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, ), topic( "检1 · 信号判断", [ ok("一句话说清唯一核心确认"), ok("点位/结构本身已够清楚"), no("说不清、靠宏观故事自圆"), no("「好像有戏」但确认模糊"), leaf("对照:1H→空间→结构→定损盈→工具", markers=["arrow-right"]), ], markers=["priority-1", "symbol-info"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, labels=["Signal"], ), topic( "检2 · 流程确认", [ ok("资金与当日额度符合"), ok("单笔/组合敞口在预算内"), no("资金或次数已触限"), no("单笔或日最坏超限 → 暂停"), no("「先开了再说」跳步"), ], markers=["priority-2", "task-start"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, labels=["Process"], ), topic( "检3 · 情绪自检", [ ok("符合系统 + 账户没问题 → 开"), ok("可接受空仓,旁观者视角"), no("怕踏空"), no("上回亏了要回本"), no("必须证明我是对的"), warn("红灯亮了,信号再好看也不开"), ], markers=["priority-3", "smiley-smile"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, labels=["Emotion"], ), topic( "复盘只记什么", [ leaf("信号:是否做了?核心写了什么?", markers=["other-note"]), leaf("流程:资金/敞口是否过关?有无跳步?", markers=["other-note"]), leaf("情绪:当时是哪一类心态?", markers=["other-note"]), warn("结果不推翻「三检是否完成」评分"), ], markers=["other-note"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, ), ], markers=["other-lock", "flag-purple"], ), t2( "开仓逻辑", [ topic( "主链条(强制)", [ leaf("1H 方向:明显 N 字;跟 1H 波段", markers=["priority-1"]), leaf("空间:空看支撑、多看阻力;≥约 2%", markers=["priority-2"]), leaf("结构:15m/5m;量级约 8h+(约 48×15m)", markers=["priority-3"]), leaf("定损盈:外沿/针尖;RR 须接受", markers=["priority-4"]), leaf("选工具:期权 或 合约(不对冲)", markers=["priority-5"]), no("任一步不过 → 空仓等待"), ], markers=["arrow-right", "symbol-info"], fill="#154360", color=C_TEXT, font_size="12pt", bold=True, labels=["主链"], ), topic( "结构形态参考", [ leaf("收敛", markers=["flag-blue"]), leaf("两段式回调", markers=["flag-dark-blue"]), leaf("箱体", markers=["flag-gray"]), leaf("假突破", markers=["flag-orange"]), ], markers=["symbol-image"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, ), topic( "期权入场", [ ok("主链条全过;结构突破/假突破成立"), leaf("一天期方向单;空间够优先虚值", markers=["star-blue"]), leaf("默认先只开期权,不上合约", markers=["symbol-info"]), leaf("尽量 16:00 后开次日到期", markers=["other-clock"]), no("不做:期期对冲、偏置壳、为开而开"), ], markers=["flag-blue", "symbol-plus"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, labels=["期权"], ), topic( "合约入场(Gate)", [ ok("主链条过关;位置极明确"), leaf("想清进场:假突破 / 结构突破", markers=["symbol-info"]), leaf("止损挂模型位(外沿/针尖)", markers=["symbol-info"]), warn("独立假突破:只做合约或空仓"), no("勿与「突破期权后再加仓」混仓"), ], markers=["flag-dark-blue", "symbol-plus"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, labels=["合约"], ), ], markers=["symbol-plus", "arrow-up-right"], ), t2( "平仓逻辑", [ topic( "期权离场", [ ok("只认:系统/规则止盈"), ok("只认:到期"), no("开仓后中间不手动平仓"), warn("紧急手平 → 标记非策略样本"), ], markers=["flag-green", "symbol-minus"], fill="#145A32", color=C_TEXT, font_size="12pt", bold=True, labels=["期权"], ), topic( "合约离场", [ ok("结构止盈为准"), ok("结构止损为准(约 5U 量级)"), leaf("等待系统/挂单结果,不情绪手平", markers=["other-clock"]), ], markers=["flag-dark-green", "symbol-minus"], fill="#145A32", color=C_TEXT, font_size="12pt", bold=True, labels=["合约"], ), topic( "持仓期盯什么", [ leaf("程序与纪律是否正常", markers=["task-done"]), no("不是浮盈浮亏数字本身"), leaf("无信号空档:空跑三检也是训练", markers=["other-lightbulb"]), ], markers=["symbol-info"], fill="#1A5276", color=C_TEXT, font_size="12pt", bold=True, ), ], markers=["symbol-minus", "flag-green"], ), ], markers=["priority-3", "arrow-right"], label="操盘", ), t1( "④ 纪律执行", [ t2( "Gate 日纪律", [ leaf("只做很明确的位置", markers=["symbol-info"]), leaf("同一位置最多两次机会(突破/假突破)", markers=["priority-2"]), no("两次都错 → 当日不再做单"), ok("离场以结构止盈/止损为准"), ], markers=["flag-dark-blue", "task-done"], ), t2( "期权日纪律", [ no("不手平;等规则止盈或到期"), leaf("一次一仓;约 10U 权利金", markers=["symbol-info"]), no("不对冲;不做每天默认开期权"), leaf("损位跟模型:外沿/针尖", markers=["symbol-info"]), ], markers=["flag-blue", "task-done"], ), t2( "开仓前自检清单", [ leaf("今日只动期权/合约?未开对冲?", markers=["task-start"]), leaf("1H 方向清楚(含 N 字)?", markers=["task-start"]), leaf("空间足够?结构量级够?", markers=["task-start"]), leaf("止损/止盈与 RR 定好?", markers=["task-start"]), leaf("工具选期权还是合约?理由写清?", markers=["task-start"]), leaf("合约:本位置第几次?今日两次用完?", markers=["task-start"]), ], markers=["other-yes", "task-start"], ), t2( "一句话版本", [ leaf("1H→空间→结构→定损盈→期权/合约", markers=["arrow-right"]), leaf("不对冲;期权不手平", markers=["flag-gray"]), leaf("一位置两次,错完收工", markers=["priority-2"]), leaf("珍惜机会,日更不是目标", markers=["star-dark-blue"]), ], markers=["star-dark-blue", "symbol-right"], ), ], markers=["priority-4", "task-done"], label="纪律", ), ], # 中心主题保持干净:不加图标/标签/备注,避免绿人、黄便签等杂乱标识 markers=None, labels=None, fill=C_ROOT, color=C_TEXT, font_size="20pt", bold=True, line=C_ROOT, ) root["structureClass"] = "org.xmind.ui.logic.right" # XMind Zen 内置主题名;客户端可识别 business sheet = { "id": tid(), "class": "sheet", "title": "执行手册与行为准则 · 商务版", "rootTopic": root, "theme": { "id": tid(), "title": "business", "centralTopic": { "id": "centralTopic", "properties": { "svg:fill": C_ROOT, "fo:color": C_TEXT, "fo:font-family": "Microsoft YaHei", "fo:font-size": "20pt", "fo:font-weight": "bold", "shape-class": "org.xmind.topicShape.roundedRect", "line-color": C_L1, "line-width": "2pt", "line-class": "org.xmind.branchConnection.roundedelbow", }, }, "mainTopic": { "id": "mainTopic", "properties": { "svg:fill": C_L1, "fo:color": C_TEXT, "fo:font-family": "Microsoft YaHei", "fo:font-size": "15pt", "fo:font-weight": "bold", "shape-class": "org.xmind.topicShape.roundedRect", "line-color": C_L2, "line-width": "1.5pt", }, }, "subTopic": { "id": "subTopic", "properties": { "svg:fill": C_L2, "fo:color": C_TEXT, "fo:font-family": "Microsoft YaHei", "fo:font-size": "12pt", "shape-class": "org.xmind.topicShape.roundedRect", "line-color": "#85C1E9", }, }, "floatingTopic": { "id": "floatingTopic", "properties": { "svg:fill": C_MUTED, "fo:color": C_TEXT, "fo:font-family": "Microsoft YaHei", }, }, "importantTopic": { "id": "importantTopic", "properties": { "svg:fill": C_WARN, "fo:color": C_TEXT, }, }, "minorTopic": { "id": "minorTopic", "properties": { "svg:fill": "#EBF5FB", "fo:color": C_TEXT_DARK, }, }, "expiredTopic": { "id": "expiredTopic", "properties": { "svg:fill": "#D5D8DC", "fo:color": C_MUTED, }, }, "calloutTopic": { "id": "calloutTopic", "properties": { "svg:fill": "#FEF9E7", "fo:color": C_WARN, }, }, "summaryTopic": { "id": "summaryTopic", "properties": { "svg:fill": "#145A32", "fo:color": C_TEXT, }, }, "boundary": { "id": "boundary", "properties": { "svg:fill": "#D6EAF8", "fo:color": C_L1, "line-color": C_L2, }, }, "summary": { "id": "summary", "properties": { "line-color": C_L1, "line-width": "2pt", }, }, "relationship": { "id": "relationship", "properties": { "line-color": C_MUTED, "line-pattern": "dash", }, }, "map": { "id": "map", "properties": { "svg:fill": "#F4F6F7", "color-list": f"{C_L1} {C_L2} #2874A6 #1ABC9C #B9770E", "line-tapered": "none", }, }, }, } return [sheet] def main() -> None: content = build_content() metadata = { "creator": {"name": "crypto_monitor", "version": "1.1"}, "activeSheetId": content[0]["id"], } manifest = { "file-entries": { "content.json": {}, "metadata.json": {}, "manifest.json": {}, } } OUT.parent.mkdir(parents=True, exist_ok=True) if OUT.exists(): OUT.unlink() with zipfile.ZipFile(OUT, "w", compression=zipfile.ZIP_DEFLATED) as zf: zf.writestr("content.json", json.dumps(content, ensure_ascii=False, indent=2)) zf.writestr("metadata.json", json.dumps(metadata, ensure_ascii=False, indent=2)) zf.writestr("manifest.json", json.dumps(manifest, ensure_ascii=False, indent=2)) print(f"wrote {OUT}") if __name__ == "__main__": main()