从种子到信号:AI FX

在上一篇文章里,AI FX 还只是一颗种子:一个代码仓库、一个 PyPI 包,以及利用自动外汇交易工具搭建学习实验室的想法。如今,它已经生根发芽。项目拥有可以运行的经纪服务端/客户端架构,OANDA 的实时数据流入内存数据库层,通过 ZeroMQ 发布,再由 Qt GUI 读取并绘制实时 K 线图。项目仍处于早期,但已经跨过重要的门槛:AI FX 不再只是搭好的框架,而是真正运行起来的系统。

AI FX 实时 EUR/CAD 界面


系统架构

当前架构有三个主要部分:

  • 负责核心数据流的 broker 进程。
  • 与外部 OANDA API 通信的 OANDA 管理器。
  • 显示行情和连接延迟信息的 Qt 客户端。

Broker 是整个系统的中心。它通过 OANDA 获取市场数据,把 K 线数据存入内存 SQLite 数据库,再通过 ZeroMQ 将更新发布给客户端。

AI FX broker/客户端架构

Qt 客户端连接到 broker,订阅 K 线主题,在新数据到达时更新界面。结果就是一个小型实时行情控制台:上方是近期 K 线数据表,下方是 K 线图,还有交易品种选择、broker 与 OANDA 延迟信息。

最后这一点很重要。这个项目不只是为了让图表动起来,而是为了构建一个能够观察自身运行状态的系统。


为什么需要 Broker

我想避免的一件事,就是把 GUI 变成交易系统本身。

GUI 很适合进行选择、渲染、调整大小,显示表格、图表和按钮等等,但它不应该负责管理数据源。

Broker 提供了清晰的职责分离:

  • OANDA 访问封装在管理器之后。
  • 客户端接收数据之前,市场数据先被规范化。
  • 内存数据库充当本地工作数据集。
  • ZeroMQ 负责 broker 和客户端进程之间的数据传输。
  • 客户端可以订阅数据,而无须自己管理数据管道。

这样的分离已经带来了好处。Qt 客户端可以断线重连,而不会成为数据的唯一真实来源。Broker 专注于自己的工作,GUI 也专注于自己的工作。


GUI 里程碑

最新的里程碑是 Qt 界面。我原本打算用 Textual 来构建客户端,但看到 Plotly 的 K 线图以后,就觉得非用它不可。

AIFX 客户端使用 Qt for Python,通过 QtWebEngineCore 渲染 Plotly 图表。

客户端启动时,历史 K 线就已加载,界面不用空着等待新数据。可以切换交易品种,近期 K 线表和图表都会更新。状态标签显示 broker 和 OANDA API 的调用延迟。

听起来也许只是外观上的改进,但它改变了整个项目的体验。

控制台日志能告诉你机器还活着,而实时图表让这一点一目了然。

它还让问题更容易暴露:缺失的 K 线、过时的订阅、延迟峰值、格式错误和数据时序异常都会直接显现。GUI 不只是好看的装饰,它还是一个诊断驾驶舱。


小周期 K 线,快速反馈

AI FX 目前专注于五秒 K 线。

这样的间隔足够短,能让系统显得生动,同时又能把行情表示为离散数据。每根 K 线概括一小段市场活动:开盘价、最高价、最低价、收盘价、成交量和时间戳。

目前项目仍处于基础设施建设阶段。工作重点不是假装系统已经可以交易,而是先铺好轨道:

  • 可靠地获取数据。
  • 干净地存储数据。
  • 可预测地发布数据。
  • 清晰地展示数据。
  • 用测试代替猜测。

交易逻辑可以以后再做。先把线路和管道接好。


测试、发布以及那些不浪漫的细节

令人意外的是,很多进展都来自并不光鲜的基础工作。

如今,核心数据类(如交易品种和 K 线)有了单元测试,也有发布流程、lint 和类型检查,以及全新安装的冒烟测试路径,确保软件包在开发目录之外也能正常运行。

这很重要,因为这样的项目转眼就可能变成一缸意大利面条。

市场数据、网络通信、异步循环、GUI 事件、序列化、绘图、打包和 API 调用,都想纠缠在一起。测试和规范发布流程,就是防止山羊闯进服务器机房的小围栏。


仍然是一台小机器

AI FX 仍然只是一台小机器。

它不是机构级交易平台,不是神奇的印钞机,也不打算与部署在交易所附近的系统拼速度,更不会假装散户交易者的网络延迟不存在。

但它正逐渐成为一个实用的实验室。

最初的想法,就是建造一个足够小、可以理解,又足够灵活、能够实验的系统。目标至今不变。

种子已经不只是埋在土里了。

现在,已经有信号了。

2026

Git Automation

Some of you may have read my Git Battles post, where I talked about how I developed and a documented a Git workflow.

My blog in Simplified Chinese

I recently built MyCount to track website visitors to my projects. I found that that over 40% of my visitors were from China, and that 35% of those used a Ch...

MyCount: Website Analytics & Marketing

I have a future project in mind which will require a Dynamic DNS service. I created BMDynIP for that purpose. After building the service, I wanted a simple a...

Animating Ax3l Playing Snake

I’ve been tinkering with various incarnations of Patrick Loeber’s Train an AI to Play Snake tutorial for a while now. It’s my relaxing goto project that’s fu...

Dynamic DNS Service

This project started as a cron job and a flatfile and -honestly- that would work perfectly well for a small home setup. Say, two or three machines. I’m curre...

Local GeoIP Database

The Bear & Moose GeoIP Project provides an easy-to-use GeoIP service for your applications and for interactive lookups.

An LLM to organize my Movies

Our first TV was a small black-and-white thing where, on rare occasions, we’d watch Animal Kingdom. Then Beta and VHS came along, and you could watch them at...

From Prototype to Product (4/4)

Fr3d worked: It could talk to the Snake Lab, propose changes to the RNN configuration, run experiments, look at the results, and try again. It proved the ide...

Prompt Engineering 101 (3/4)

The Snake Lab had become a proper server, with a ZeroMQ API, configuration validation, a database, and a way to run experiments independently of the client. ...

The Evolution of Snake Lab (2/4)

In my last post, I setup a locally hosted LLM running on an old HP Z440 and wrote a crude little conversation loop. I generated random numbers, fed them to t...

Local LLM Writes Haikus (1/4)

This is part one of a four part blog series. In this post, I download, install and setup some software to prompt a local LLM to write haikus…

From Seed to Signal: AI FX

In the first post, AI FX was still mostly a seed: a repo, a PyPI package, and an idea about using automated FOREX tooling as a learning lab. Since then, the ...

Simulating the Power Grid

A potential client pointed me to Empowering the Energy Transition Through Fast and Flexible Network Simulation. The article describes an Open Source project,...

Delphi in a Day

I have a prospective client who runs a small group of technology businesses, at least one of which integrates with clients using the Delphi programming lan...

A Small Experiment: AI FX

I’ve spent some time around trading systemsL At Merrill Lynch, I supported the Order Audit Trail System (OATS), a compliance system required by NASDAQ. Its p...

Back to top ↑

2025

My Art on Etsy

I setup an Etsy Storefront to sell high quality, museum grade prints of some of my artwork.

Python systemctl Wrapper

I’ve been working on Db4E, my Monero deployment, operations and analytics platform. It uses Linux systemd to spin up manage Monero, P2Pool and XMRig instance...

AI Snake Lab

AI Snake Lab is an interactive reinforcement learning sandbox for experimenting with AI agents in a classic Snake Game environment — featuring a live Textual...

The Power of Pictures

You know that saying, “A picture is worth a thousand words.”? In programming, I’d argue it can be worth a thousand lines of code…

Caring About Constants

This post is about using constants in your code. Why it matters, what the benefits are and how you can do it well. I’m sad to say, I learned this the hard wa...

Why I Built Db4E

When I first started experimenting with Monero mining and self-hosted infrastructure, I did what everyone else does: I downloaded the Monero software, the P2...

Releasing with Git

Let me be honest: Git has punched me in the face more times than I can count. Every time I think I’ve got a smooth release flow down, Git yells, “Not so fast...

Documentation Matters

I was burned by opaque documentation: I’ve been building a modern terminal UI in Python using the excellent Textual framework. It’s sharp, fast, and honestly...

Textual Replaces ApexCharts

The original reporting system was a set of static dashboards built using GitHub Pages, JavaScript, and ApexCharts. It pulled data from my mining setup — via ...

Pivot to Textual

I’ve been deep in the trenches with my Db4E project — pulling together Monero mining infrastructure, MongoDB integration, and a bunch of orchestration magic....

Released Db4E SystemD

I recently published a small Python module to PyPI and GitHub: db4e-systemd, a lightweight wrapper around systemctl that lets you control services (start, st...

NIKU Farms

I received my order from NIKU Farms, YAY! It’s a meat delivery that my sister, Corinna Ghaznavi, gifted me this Christmas. Every two months I receive this am...

The Main Website

As part of my goal to be more visible in the world, I setup this domain i.e. https://osoyalce.com. I use it to publish information about the projects I’m wor...

Reviving the Blog

It’s been a while since I started and then abandoned this blog. My last post was in June of 2024!!

Changing the Blog Site’s Layout

I decided that I didn’t like the way that the main blog page looks. I am using GitHub to host the website and am using a fork of the jekyll/minima theme. My ...

Back to top ↑

2024

Aquaponics Update #1

It’s in the construction phase. I need to complete the water circulation process. I bought a fiber glass kit for this (and also to fix my kitchen sink!).

What I’m working on

The XMR Mining Farm complete with this eye-popping chart The Bear and Moose Knowledge Base My resume MyZODB - A Place to Store Everything

Back to top ↑