2026-11-02 · 开发日志 / Development journal / Entwicklungstagebuch · Windows 0.2.0 / VPS 0.2.1

Windows strategy computation, VPS execution and OKX demo accounts; shared EXE and browser interface
本地计算、VPS 执行与独立模拟账户 / Local computation, VPS execution and separate demo accounts / Lokale Berechnung, VPS-Ausführung und getrennte Demokonten

中文|把 BTC 研究脚本做成一个能解释自己状态的 EXE

这次项目起于一个很直接的念头:比较几套开源 BTC 量化方案,再把值得继续研究的两套放进同一个控制台。我希望双击 EXE 就能看到策略、账户和订单,在浏览器里也能操作同一套界面。真正做起来之后,花时间最多的部分是进程退出、订单回执和故障恢复。

截至 11 月 2 日,桌面和网页更新到 0.2.0,VPS 执行核心修到 0.2.1。它已经能运行两套策略、展示阶段和行情,并配置模拟执行参数。它仍是依赖当前研究环境的工作区版本,真实资金通道禁用,完整设计验收没有完成。

先比较,再决定继续做什么

我先把八个“项目+具体策略或模型”放到统一研究账本里比较,覆盖 TradingAgents、AI Hedge Fund、Vibe-Trading、Qlib、vn.py、Freqtrade,以及后来留下的 Fincept 和 NautilusTrader。比较的是本次调用的实现,不能把结果当作这些开源项目全部能力的排名。

最终纳入 64 个共同结果:每个项目各四个 90 天窗口和四个 14 天窗口。各窗口独立从 1,000 USDT 开始,计入每边 0.05% 手续费、0.02% 不利滑点及历史资金费;每四小时决策,下一分钟延迟执行。八小时是预算上限,下一完整轮次预计无法在剩余预算内完成,因此提前收尾。中期和短期均值各占一半,得到综合分数。

Eight implementations compared on common historical windows; passive-long baseline 7.0715, Fincept 6.7932, NautilusTrader 6.6488
共同历史窗口的综合分数,单位为百分点。它不是连续账户收益,也不是年化收益。

Fincept+历史选择器的分数为 6.7932,NautilusTrader+EMA 为 6.6488,相差约 0.14 个百分点。被动做多基准为 7.0715,高于两者。Fincept 的最大单窗口回撤约 22.07%,Nautilus 约 18.66%。这个结果足够让我继续做工程验证,但不足以宣布找到了稳定盈利的策略。Qlib 与 vn.py 在本轮共用模型和仓位配置;Vibe-Trading 的零收益来自没有成交。

留下两套能逐步检查的规则

Fincept 这一路使用历史选择器,在六组 SMA/EMA 候选中按历史评分定期选择一组,再用新收盘的四小时 K 线计算方向。NautilusTrader 这一路固定使用 EMA10/EMA20,并过滤相对于近期波动过弱的信号。两路都结合波动率生成仓位建议。

这两套当前实现没有调用大语言模型,不需要模型 API 或 GPU 推理。我在开发中使用 Codex 协助设计、编程和排错;运行时的交易判断仍由这些数学规则完成。研究信号和执行仓位也分开处理:图上的 short 表示计算方向,只有核实成交后才算实际持仓。

断电问题决定了 Windows 与 VPS 的分工

我一度考虑只在 Windows 上运行,并加入 UPS。后来取消 UPS 方案,回到本地计算、自己的 VPS 执行。原有小型 VPS 的内存和软件环境不适合原样搬入两套完整研究环境,因此把它的职责缩到执行、对账和保护。本地 EXE 与网页共用 React 页面和后台,Windows 后台管理两路计算进程;桌面外壳使用 .NET。

默认设计每五秒发送健康心跳,连续三十秒没有有效心跳时,VPS 锁定新增风险、处理开仓挂单,并按实际平均开仓价建立默认保护。多仓止损在均价下方,空仓在上方;图中的 1% 是设计和模拟示例。默认保护在失联接管后建立,因此接管前存在等待窗口。建立后的交易所原生条件单能在本机离线时继续生效,但不能保证成交价格或消除亏损。

我把“解除报警”和“恢复交易”做成了两个动作。连接恢复、账户读取得到确认,且空仓、无挂单、无未知订单之后,才允许解除报警;解除之后保持暂停。断线重连不会直接重新开仓。网页和 EXE 关闭也不会顺手杀掉后台,真正停止本地服务有单独的托盘入口。

Early unified trading console overview in an isolated simulator, showing two strategy cards and protection status
早期隔离模拟器界面,用来验证两策略卡片、暂停状态和保护说明。图中数值是演练数据,不是 OKX 或真实资金收益。

三个故障,把“能启动”推到了“能排错”

第一类是 50011 限流。账户核验失败后,重复查询增加了压力。修复加入查询节奏和冷却,同时把“合约账户模式”“单向持仓模式”这些前提显示出来。限流和账户模式分别核验,避免把不同问题揉成一个“连接失败”。

第二类是 Windows 的 WinError 5 / 32。旧计算进程残留,多份进程同时替换同一个状态文件,发生文件占用冲突。仅仅重开窗口无法解决。我清理了残留进程,加入策略独占锁、父进程退出联动及原子替换重试。修复阶段通过 43 项自动化测试,约九十秒现场观察没有再次出现文件冲突;0.2.0 又增加了桌面单实例处理。

第三类在 11 月 2 日晚出现:账户读取失败,约 1.8 秒后又核验成功,系统进入“已空仓、待解除报警”。旧日志里的错误字符串是空白,无法确认具体接口或底层异常,更不能直接归因于限流。0.2.1 为只读 GET 的传输异常增加一次有界重试,补记账户、接口和异常类型,并清理失败快照中尚未退出的并行查询。

下单等 POST 请求没有跟着自动重发。订单可能已经被交易所接受,只是回执或后续查询超时;这种情况必须按原订单编号核验,并保留未知状态。把超时简单解释为“没有下单”,会引入重复仓位。

Historical demo-account alarm screen: healthy account reads, flat positions and healthy heartbeats are required before clearing an alarm
历史模拟账户报警页。条件满足后可以解除,解除后仍保持暂停;截图记录的是当时状态。

0.2.0 开始把参数解释清楚

最初执行端固定一倍杠杆。后来我把预算、允许方向、杠杆方式和上限、仓位比例方式、比例上限、最小增仓差额做成每个策略的独立选项,并给出解释和参考值。预算、比例和杠杆共同决定目标名义金额,例如 1,000 × 20% × 3 = 600 USDT;最终仍受额度、权益和合约精度约束。这只是公式示例。

页面也加上了两套策略的流程图、当前阶段、下一根 K 线时间、收益与仓位曲线,以及 BTC 行情。收益记录从新版基线开始,出入金不计作利润;同一子账户同合约上的人工交易仍可能影响展示,尚不能完整区分机器人归因。我没有把研究均线参数混进执行设置,也没有为了画满曲线拼接升级前的历史。

写到这里,完成和未完成都要说清

0.2.1 的记录有 65 项自动化测试通过,覆盖只读重试、持续故障锁定、POST 不重放及订单未知语义。0.2.0 另有三项桌面生命周期组件检查。这里的测试数量与原设计的 58 条完整验收是不同口径,不能互相替代。短时现场观察也不能代替长期可靠性验证。

接下来还要完成连续 OKX 模拟运行、实际原生保护单联调、极端断网组合、干净 Windows 安装,以及服务最小权限迁移。这次最有用的进展,是让“正在计算”“等待收盘”“已暂停”和“订单结果未知”有了各自的状态与处理路径。窗口能打开之后,后台究竟在做什么,终于可以逐项追问。


English | Building a BTC research console that can explain its state

I started with a practical goal: compare several open-source BTC trading implementations, then put two candidates into one console. I wanted an EXE that opened with a double-click and a browser interface showing the same strategies, accounts and orders. Process shutdown, missing order responses and recovery rules ended up taking much of the work.

By 2 November, the desktop and web interface had reached 0.2.0, with the VPS execution core patched to 0.2.1. The application runs two strategies and exposes their stages and demo execution settings. It remains a workspace build tied to my research environments. Real-money execution is disabled, and full design acceptance is unfinished.

The comparison that shaped the project

I compared eight specific project-and-strategy or model combinations through a shared research ledger: TradingAgents, AI Hedge Fund, Vibe-Trading, Qlib, vn.py, Freqtrade, Fincept and NautilusTrader. These results describe the implementations I used, rather than the complete capabilities of each project.

The final comparison included 64 common results: four 90-day and four 14-day windows per implementation. Each window started independently with 1,000 USDT. The ledger included a 0.05% fee per side, 0.02% adverse slippage and historical funding, with four-hour decisions executed in the following minute. Eight hours was the budget ceiling; I stopped early because another complete round was unlikely to fit. The composite score weights the medium- and short-window mean returns equally.

Composite historical-window scores for eight implementations and a passive-long baseline
Percentage-point scores across independent historical windows; these are neither continuous account returns nor annualized returns.

Fincept with the historical selector scored 6.7932 and NautilusTrader with EMA scored 6.6488, a difference of about 0.14 percentage points. A passive-long baseline scored 7.0715. Their largest single-window drawdowns were approximately 22.07% and 18.66%, respectively. That justified further engineering experiments without establishing a durable trading advantage. Qlib and vn.py shared a model and sizing configuration in this run; Vibe-Trading's zero return came from making no trades.

Two strategies whose decisions I could inspect

The Fincept branch periodically scores six SMA/EMA candidates on historical data, chooses one and computes direction from newly closed four-hour candles. The NautilusTrader branch uses fixed EMA10/EMA20 rules and filters signals that are weak relative to recent volatility. Both produce volatility-dependent position suggestions.

Neither running strategy calls a large language model or requires GPU inference. Codex helped with design, implementation and debugging; mathematical rules generate the runtime decisions. I also kept signals separate from execution: a displayed short direction is not a confirmed short position.

Power loss defined the architecture

I briefly considered a Windows-only setup with a UPS, then dropped the UPS plan and returned to local computation with execution on my own VPS. The small existing VPS lacked the memory and software environment for moving both full research environments unchanged. Windows therefore runs the strategy workers, while the VPS handles execution, reconciliation and protection. A .NET desktop shell and the browser share the React interface and local backend.

The default design sends a healthy heartbeat every five seconds. After thirty seconds without a valid heartbeat, the VPS blocks new risk, handles pending opening orders and establishes protection relative to the actual average entry price. A long stop sits below that price; a short stop sits above it. The 1% distance shown in the design is a demo example. Default protection is established after takeover, leaving a waiting interval beforehand. Once established, an exchange-native conditional order can survive a local outage, but it cannot guarantee an execution price or eliminate losses.

Clearing an alarm and resuming trading are separate actions. Recovery requires healthy reads and heartbeats, flat positions and no pending or unknown orders. Clearing leaves the system paused. Reconnecting does not reopen positions. Closing the EXE or browser also leaves the background service running; stopping that service has its own tray action.

Early shared console with two strategy cards in the isolated simulator
Early isolated-simulator interface. Its balances and outcomes are test data, not OKX results or real-money returns.

Three failures that changed the implementation

The first was 50011 rate limiting. Repeated account checks after a failure added pressure. I introduced request pacing and cooldowns, and made contract-account and one-way-position prerequisites visible. Rate limiting and account configuration needed separate diagnosis.

The second was Windows WinError 5 / 32. Leftover workers tried to replace the same state file. Reopening the window could not fix competing writers. I cleaned up the workers and added an exclusive strategy lock, parent-process lifetime handling and bounded retries around atomic replacement. That patch passed 43 automated tests and a roughly ninety-second observation without another file conflict. Version 0.2.0 also added a single-instance desktop guard.

The third appeared on the evening of 2 November. An account read failed and recovered around 1.8 seconds later, leaving the console flat and locked pending alarm clearance. The old exception string was empty, so the evidence could not identify a specific endpoint or establish rate limiting as the cause. Version 0.2.1 adds one bounded retry for transport failures on read-only GET requests, records the account, endpoint and exception type, and cancels remaining concurrent reads when a snapshot fails.

Order-submission POST requests are not automatically replayed. An exchange may already have accepted an order when its response or a later lookup times out. The system must reconcile the original order identifier and preserve uncertainty instead of submitting a replacement.

Historical demo alarm page showing the conditions for clearing an incident
Historical demo-account alarm screen. Meeting the conditions permits clearance; trading remains paused afterward.

Making configuration understandable

The early executor enforced one-times leverage. In 0.2.0 I exposed per-strategy budgets, allowed directions, leverage modes and caps, sizing modes and caps, and minimum position-increase differences, with explanations and reference values. For example, a 1,000 USDT budget multiplied by 20% and three-times leverage gives a 600 USDT target notional before equity, exposure and contract-precision limits. This is an arithmetic example.

I added strategy flow diagrams, current stages, the next candle time, return and position charts, and BTC market data. Return history begins at the new baseline and excludes deposits and withdrawals from profit. Manual activity in the same subaccount and contract can still affect the display; complete attribution is unfinished. Research indicator parameters remain frozen.

Where I stopped this entry

The 0.2.1 record shows 65 passing automated tests, including bounded read retries, persistent locking, POST non-replay and ambiguous-order handling. Version 0.2.0 also has three desktop lifecycle component checks. These counts do not mean the original 58 full design acceptance cases passed, and short observations do not establish long-term reliability.

Continuous OKX demo operation, actual exchange-native protection tests, combined outage scenarios, clean Windows installation and a least-privilege service migration remain ahead. The useful progress is that computing, waiting for candle close, paused and unknown-order states now have explicit meanings and recovery paths. I can inspect what the background service is doing after the window opens.


Deutsch | Eine BTC-Konsole entwickeln, die ihren Zustand erklärt

Am Anfang wollte ich mehrere quelloffene BTC-Handelsansätze vergleichen und zwei Kandidaten in einer gemeinsamen Oberfläche bedienen. Ein Doppelklick auf die EXE sollte reichen; im Browser sollten dieselben Strategien, Konten und Orders erscheinen. Viel Arbeit steckte schließlich im Beenden von Prozessen, in fehlenden Orderantworten und in den Regeln für den Wiederanlauf.

Am 2. November stehen Desktop und Weboberfläche bei Version 0.2.0, der Ausführungskern auf dem VPS bei 0.2.1. Zwei Strategien laufen, ihre Phasen und die Parameter der Demoausführung sind sichtbar. Die Anwendung bleibt eine an meine Forschungsumgebung gebundene Arbeitsversion. Der Handel mit echtem Geld ist deaktiviert, die vollständige Abnahme ist offen.

Der Vergleich vor der Entwicklung

Ich verglich acht konkrete Kombinationen aus Projekt und Strategie beziehungsweise Modell über ein gemeinsames Forschungsbuch: TradingAgents, AI Hedge Fund, Vibe-Trading, Qlib, vn.py, Freqtrade, Fincept und NautilusTrader. Die Ergebnisse gelten für die eingesetzten Implementierungen und bewerten nicht sämtliche Funktionen dieser Projekte.

Am Ende gingen 64 gemeinsame Ergebnisse ein: je vier Zeitfenster mit 90 Tagen und vier mit 14 Tagen pro Implementierung. Jedes Fenster begann unabhängig mit 1.000 USDT. Berücksichtigt wurden 0,05 % Gebühr je Handelsseite, 0,02 % nachteilige Slippage und historische Funding-Zahlungen. Entscheidungen erfolgten alle vier Stunden, die Ausführung in der folgenden Minute. Acht Stunden waren die Budgetobergrenze. Für eine weitere vollständige Runde reichte die verbleibende Zeit voraussichtlich nicht, deshalb endete der Lauf früher. Mittlere und kurze Fenster gehen mit jeweils 50 % in den Gesamtwert ein.

Gesamtwerte der acht Implementierungen und einer passiven Long-Benchmark in gemeinsamen historischen Fenstern
Gesamtwerte in Prozentpunkten aus unabhängigen historischen Fenstern. Keine durchgehende Kontorendite und keine Jahresrendite.

Fincept mit historischem Selektor erreichte 6,7932, NautilusTrader mit EMA 6,6488. Der Abstand betrug rund 0,14 Prozentpunkte. Eine passive Long-Benchmark lag mit 7,0715 darüber. Der größte Drawdown innerhalb eines einzelnen Fensters betrug etwa 22,07 % beziehungsweise 18,66 %. Das war ein Anlass für weitere technische Versuche, aber kein Nachweis eines dauerhaften Handelsvorteils. Qlib und vn.py verwendeten in diesem Lauf dasselbe Modell und dieselbe Positionskonfiguration. Vibe-Trading erzielte null Rendite, weil keine Geschäfte zustande kamen.

Zwei nachvollziehbare Regelwerke

Der Fincept-Zweig bewertet regelmäßig sechs SMA-/EMA-Kandidaten anhand historischer Daten, wählt einen aus und berechnet die Richtung mit neu abgeschlossenen Vierstundenkerzen. Der NautilusTrader-Zweig arbeitet mit festen EMA10-/EMA20-Regeln und filtert Signale, die im Verhältnis zur jüngsten Volatilität zu schwach sind. Beide liefern volatilitätsabhängige Vorschläge für die Positionsgröße.

Keine der beiden laufenden Strategien ruft ein großes Sprachmodell auf oder benötigt GPU-Inferenz. Codex half bei Entwurf, Programmierung und Fehlersuche; die Handelsentscheidungen entstehen zur Laufzeit aus mathematischen Regeln. Ein angezeigtes short-Signal bleibt außerdem von einer bestätigten Short-Position getrennt.

Der Stromausfall bestimmt die Aufgabenteilung

Zwischendurch erwog ich einen reinen Windows-Betrieb mit USV. Später verwarf ich die USV und kehrte zur lokalen Berechnung mit Ausführung auf meinem eigenen VPS zurück. Dem kleinen vorhandenen VPS fehlten Speicher und passende Laufzeitumgebungen, um beide vollständigen Forschungsumgebungen unverändert zu übernehmen. Deshalb berechnet Windows die Signale, während der VPS Orders, Abgleich und Schutz verwaltet. Eine .NET-Desktophülle und der Browser nutzen dieselbe React-Oberfläche und denselben lokalen Hintergrunddienst.

Im Standardentwurf kommt alle fünf Sekunden ein gültiges Lebenszeichen. Fehlt es dreißig Sekunden lang, sperrt der VPS zusätzliche Risiken, bearbeitet offene Eröffnungsorders und richtet einen Schutz relativ zum tatsächlichen durchschnittlichen Einstiegspreis ein. Bei Long liegt die Stoppschwelle darunter, bei Short darüber. Die gezeigten 1 % sind ein Entwurfs- und Demobeispiel. Standardmäßig entsteht dieser Schutz erst nach der Übernahme bei Verbindungsverlust; davor besteht eine Wartephase. Eine eingerichtete börsenseitige bedingte Order kann einen lokalen Ausfall überstehen, garantiert aber weder Ausführungskurs noch Verlustfreiheit.

Alarmaufhebung und Handelsfortsetzung sind getrennt. Erst nach bestätigtem Kontozugriff, gesunden Lebenszeichen, geschlossenen Positionen und ohne offene oder ungeklärte Orders lässt sich der Alarm aufheben. Danach bleibt der Handel pausiert. Eine neue Verbindung öffnet keine Positionen. Auch das Schließen von EXE oder Browser beendet den Hintergrunddienst nicht. Dafür gibt es einen eigenen Befehl im Infobereich.

Frühe gemeinsame Konsole mit zwei Strategiekarten im isolierten Simulator
Frühe Oberfläche des isolierten Simulators. Kontostände und Ergebnisse sind Testdaten, keine OKX-Ergebnisse oder Echtgeldrenditen.

Drei Fehler, die den Aufbau verändert haben

Zuerst trat die Ratenbegrenzung 50011 auf. Wiederholte Kontoprüfungen nach einem Fehler erhöhten die Last. Ich ergänzte Abfrageabstände und Abkühlzeiten und machte Voraussetzungen wie Vertragskontomodus und Einweg-Positionsmodus sichtbar. Ratenbegrenzung und Kontoeinstellung mussten getrennt geprüft werden.

Danach meldete Windows WinError 5 / 32. Zurückgebliebene Berechnungsprozesse ersetzten gleichzeitig dieselbe Zustandsdatei. Ein neues Fenster löste diesen Konflikt nicht. Ich beendete die alten Prozesse und ergänzte eine exklusive Strategiesperre, die Bindung an den Elternprozess sowie begrenzte Wiederholungen beim atomaren Dateiersatz. Der Patch bestand 43 automatisierte Tests; in einer Beobachtung von rund neunzig Sekunden trat kein weiterer Dateikonflikt auf. Version 0.2.0 verhindert zusätzlich mehrere Desktopinstanzen.

Am Abend des 2. November scheiterte eine Kontoabfrage und funktionierte etwa 1,8 Sekunden später wieder. Die Konsole blieb ohne Positionen gesperrt, bis der Alarm aufgehoben würde. Im alten Protokoll war der Fehlertext leer. Daraus ließ sich weder ein konkreter Endpunkt noch eine Ratenbegrenzung als Ursache ableiten. Version 0.2.1 wiederholt reine GET-Lesezugriffe bei Transportfehlern einmal innerhalb einer festen Zeitgrenze. Sie protokolliert Konto, Endpunkt und Ausnahmetyp und beendet übrige parallele Abfragen, wenn eine Momentaufnahme fehlschlägt.

POST-Anfragen zur Orderaufgabe werden nicht automatisch wiederholt. Die Börse kann eine Order bereits angenommen haben, obwohl die Antwort oder die anschließende Abfrage ausbleibt. Dann muss das System die ursprüngliche Orderkennung abgleichen und den ungeklärten Zustand erhalten. Eine neue Order könnte sonst die Position verdoppeln.

Historische Demokonto-Alarmseite mit Voraussetzungen für die Alarmaufhebung
Historische Alarmseite aus dem Demobetrieb. Nach erfüllten Bedingungen ist die Aufhebung möglich; der Handel bleibt anschließend pausiert.

Parameter brauchen Erklärungen

Die erste Ausführungsversion begrenzte den Hebel fest auf eins. Mit 0.2.0 kamen getrennte Strategiebudgets, erlaubte Richtungen, Hebelmodi und Obergrenzen, Positionsmodi und Größenlimits sowie Mindestdifferenzen für Positionsvergrößerungen hinzu. Jede Einstellung erhielt eine Erklärung und Referenzwerte. Ein Budget von 1.000 USDT mal 20 % mal Hebel drei ergibt beispielsweise 600 USDT Zielnominalwert, bevor Eigenkapital-, Risiko- und Kontraktpräzisionsgrenzen greifen. Das ist ein Rechenbeispiel.

Hinzu kamen Ablaufdiagramme, die aktuelle Phase, der nächste Kerzenschluss, Rendite- und Positionskurven sowie BTC-Marktdaten. Die Renditehistorie beginnt mit einer neuen Basis; Ein- und Auszahlungen zählen nicht als Gewinn. Manuelle Geschäfte im selben Unterkonto und Kontrakt können die Anzeige beeinflussen. Eine vollständige Zuordnung zum Roboter fehlt noch. Die Forschungsparameter der Indikatoren bleiben unverändert.

Der Stand dieses Eintrags

Für 0.2.1 sind 65 bestandene automatisierte Tests dokumentiert, darunter begrenzte Lesewiederholungen, dauerhafte Sperren, ausbleibende POST-Wiederholung und ungeklärte Orderergebnisse. Zu 0.2.0 gehören außerdem drei Komponentenprüfungen des Desktop-Lebenszyklus. Diese Zahlen ersetzen nicht die ursprünglich vorgesehenen 58 vollständigen Abnahmefälle. Kurze Beobachtungen belegen auch keine langfristige Zuverlässigkeit.

Offen bleiben längerer OKX-Demobetrieb, tatsächliche Tests der börsenseitigen Schutzorders, kombinierte Ausfälle, die Installation auf einem sauberen Windows-System und ein Dienstkonto mit minimalen Rechten. Der greifbare Fortschritt liegt in den Zuständen: Berechnung, Warten auf Kerzenschluss, Pause und ungeklärtes Orderergebnis haben jetzt eigene Bedeutungen und Wiederanlaufregeln. Nach dem Öffnen des Fensters kann ich nachvollziehen, was im Hintergrund geschieht.


依据 / Basis / Grundlage: 2026-11-01 common-window backtest report; TradingConsole milestones 0.2.0 and 0.2.1; archived development records. Screenshots show historical simulator/demo states. 本文记录软件开发与历史实验,不提供收益承诺。 / This entry records software development and historical experiments, with no return promise. / Dieser Eintrag dokumentiert Softwareentwicklung und historische Versuche ohne Renditeversprechen.