夜雨聆风学习资料网

ARTICLE · 1299855

AiTrader助手策略看板前端实现

AiTrader助手策略看板前端实现

前两篇聊了 AiTrader 策略助手的设计思路和后端实现,这篇轮到前端。说实话,前端这块写起来比我预想的麻烦。

麻烦在哪?数据量不算大,但维度很杂:长线看日线,覆盖 30 个资产;中线看 4 小时,4 个资产;短线看 1 小时,也是 4 个。交易员希望一眼看完,不想来回切页面。后台那种一行行的表格肯定不行,看久了眼花,关键信号还容易看漏。

下面按我们实际做的顺序讲:先是路由怎么挂,再是几个主要区块,最后是上线前踩的两个坑。坑那部分我觉得最有参考价值,赶时间的可以直接跳过去。

一、路由:挂在仪表盘下面

我们项目的路由是混合模式,菜单权限由后端下发,页面骨架在前端静态注册。看板放在「仪表盘」下面,跟工作台、BTC ETF、WLFI 几个看板并排。

在 router/routes.ts 的 dashboardLayoutChildren 里加一条就行:

1
2
3
4
5
6
7
8
9
10
{  path: "assistant",  name: "DashboardAssistant",  component: () => import("@views/dashboard/assistant/index.vue"),  meta: {    title: "menus.dashboard.assistant",    icon: "ri:robot-2-line",    keepAlive: true,  },},

keepAlive 记得打开。交易员经常在几个看板之间来回切,每次切回来都重新请求一遍,体验很差。

组件分了两层。外面那层 index.vue 只干一件事:挂载组件,顺便定个 name,不然 keepAlive 认不出来。

1
2
3
<template>  <AssistantDashboard /></template>

真正的逻辑都在 AssistantDashboard.vue 里:拉数据、筛选、渲染,全在这。这么拆的好处是,以后这个看板要搬到别的地方用,外壳换掉就行。

二、页面上的几个区块

从上往下大概五块,挑几块说。

1. 顶部状态栏

最上面放了一个小绿点,用 Tailwind 的 animate-pulse 让它一闪一闪,旁边写着最后更新时间。

1
2
<span class="inline-block w-2 h-2 rounded-full bg-emerald-500 animate-pulse" /><span>更新时间: {{ overviewData?.updated_at }}</span>

这个点看着不起眼,但挺管用。后端是定时任务在跑,任务挂了的话时间就不动了,交易员扫一眼就知道数据是不是新的。

旁边还有个「同步策略数据」按钮,用 ElDropdown 做成下拉,可以选同步全部,或者只同步长线(每天 08:00)、中线(每 4 小时)、短线(每 1 小时)。点了之后后端异步去采,按钮上转个 loading。

2. 三个周期的概览卡片

1D、4H、1H 各一张卡片,主要显示多头占比和下次更新的倒计时。多空占比用一根条来画,底色是淡红,上面盖一层绿,绿色宽度就是多头百分比:

1
2
3
4
5
6
<div class="w-full h-2 rounded-full bg-rose-500/20 overflow-hidden flex">  <div    class="h-full bg-emerald-500 transition-all duration-500"    :style="{ width: `${overviewData.summaries.long.bull_ratio}%` }"  /></div>

加了 transition,数据刷新的时候条会滑过去,不是一下跳过去,看着舒服一点。

3. 共振矩阵

这是整个看板最核心的部分。BTC、ETH、LTC、XRP 四个币,每个一张卡片,里面横着排日线、4H、1H 三个周期,每个周期写清楚方向、参考价、生效时间。

卡片的边框和背景色跟着共振状态变。写了个函数,按状态返回不同的 class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const getResonanceCardClass = (status: string) => {  switch (status) {    case "STRONG_BULL":   // 三个周期都看多,绿      return "border-emerald-500/40 bg-emerald-50/10 dark:bg-emerald-950/20";    case "STRONG_BEAR":   // 三个周期都看空,红      return "border-rose-500/40 bg-rose-50/10 dark:bg-rose-950/20";    case "BULL_PULLBACK": // 长多短空,算回调,蓝      return "border-indigo-500/30 bg-indigo-50/10 dark:bg-indigo-950/20";    case "BEAR_REBOUND":  // 长空短多,算反弹,紫      return "border-purple-500/30 bg-purple-50/10 dark:bg-purple-950/20";    default:      return "border-slate-200 dark:border-slate-800 bg-slate-50/30 dark:bg-slate-900/30";  }};

颜色我们调了好几轮。一开始透明度给得太高,四张卡片一亮起来,整屏花花绿绿,反而看不出重点。后来压到 /10、/20 这个程度,只是淡淡一层底色,边框稍微明显些,刚好。

4. 长线 30 个资产的列表

30 张卡片排成网格,上面有多空筛选和币种搜索。数据一次全拿回来了,筛选直接在前端用 computed 做,不用再请求后端:

1
2
3
4
5
6
7
8
9
10
11
12
const filteredLongList = computed(() => {  if (!overviewData.value?.long_list) return [];  return overviewData.value.long_list.filter((item: StrategyItem) => {    if (filterAction.value !== "all" && item.action.toLowerCase() !== filterAction.value) {      return false;    }    if (searchSymbol.value.trim()) {      return item.symbol.toLowerCase().includes(searchSymbol.value.trim().toLowerCase());    }    return true;  });});

30 条数据,这么写完全够用,输入的时候基本感觉不到延迟。

三、踩过的两个坑

坑一:文字被卡片底边切掉半行

第一版里,每张资产卡片下面有一段策略提示,我图省事加了 line-clamp-2,只显示两行:

1
2
3
<p class="text-[11px] text-slate-500 mt-2 line-clamp-2 bg-slate-50 p-1.5 rounded">  {{ item.action_details }}</p>

结果有些提示写得很长,比如「价格若在 2026/10/12 08:00:00 低于 162.73 USDT,长线助手预测出现下跌趋势,可考虑卖出。」这种,要折三行。卡片又没设最小高度,第三行正好被下边框拦腰截断,露出半截字。

难看是一回事,更要命的是被截掉的恰好是价格。交易员要的就是这个数。

改法分两步:

第一,卡片统一给个最小高度 min-h-[195px],再加 flex flex-col justify-between。这样不管内容长短,一行五张卡片高度都是齐的,底部的收益率也能对齐。

第二,去掉 line-clamp-2,行高固定成 leading-[18px],文字容器加 flex-1 让它自己撑开,三行就完整显示三行。顺手加了个 title,鼠标放上去能看全文。

改完的结构大概是这样(省略了部分内容):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="symbol-card p-3.5 rounded-xl border flex flex-col justify-between min-h-[195px]">  <div class="flex flex-col flex-1">    <div class="flex items-center justify-between">...</div>    <div class="mt-2.5 flex items-baseline justify-between text-xs">...</div>    <div      class="text-[11px] leading-[18px] mt-2.5 p-2 rounded-lg flex-1 flex items-center"      :title="item.action_details || ''"    >      <span>{{ item.action_details || '暂无详细提示' }}</span>    </div>  </div>  <div class="mt-3 pt-2.5 border-t text-[11px] flex items-center justify-between">    <span>12M 策略收益:</span>    <span class="font-mono font-bold">...</span>  </div></div>

坑二:价格后面一长串小数

后端给的阈值价是回测算出来的,精度高得离谱。AAVE 是 162.72552341327236,ADA 是 0.22372494668304982。原来的 formatPrice 只处理了大于 1000 的情况,小于 1000 就原样输出,一串数字把右边挤得满满当当。

后来按价格大小分了三档:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const formatPrice = (val?: string | null) => {  if (!val) return "-";  const num = Number(val);  if (isNaN(num)) return val;  if (num >= 1000) {    // 比如 $65,230.50    return `$${num.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;  } else if (num >= 1) {    // 比如 $162.73    return `$${num.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 4 })}`;  } else {    // 比如 $0.2237    return `$${num.toLocaleString("en-US", { minimumFractionDigits: 4, maximumFractionDigits: 6 })}`;  }};

为什么小于 1 的要留四到六位?因为很多小币本身就几分钱,只留两位的话,ADA 就成了 $0.22,跟 0.2237 差了不少,阈值价这么显示是要出问题的。

改完之后,BTC 这种几万刀的和几毛钱的小币放在一起,都能显示得比较干净。

四、最后

回头看,这个看板前端没用什么特别的技术,Vue 3 加 Tailwind,大部分人都会。真正花时间的是那些细节:颜色深一点浅一点,文字截不截断,小数留几位。每一处都不大,但交易员每天要盯着看好几个小时,这些地方不顺手,用起来就很难受。

到这里,策略助手看板的设计、后端、前端三篇就写完了。有在做类似东西的朋友,欢迎留言交流,也欢迎拍砖。

#AiTrader #Fastapi #Python #量化 #量化系统 #量化策略 #策略
相关阅读:
[创新技术阁][AiTrader]利用CCXT构建公共数据服务之架构设计
[创新技术阁][AiTrader]利用CCXT构建公共数据服务之WebSocket Pub Sub 广播池核心架构
[创新技术阁][AiTrader]利用CCXT构建公共数据服务之WebSocket Pub Sub 通信协议与数据格式定义
[创新技术阁][AiTrader]WebSocket 发布-订阅(Pub Sub)广播模式架构详解
[创新技术阁][AiTrader]新增ETF信息展示和定时任务
[创新技术阁][AiTrader]现货ETF数据看板实现设计方案
[创新技术阁][AiTrader]现货ETF数据看板后端实现
AiTrader现货ETF前端高阶可视化与交互实现解析
多周期共振与决策透视:AiTrader AI策略助手看板架构设计方案

回首页,搜索你想要的文档

在首页搜索框输入关键词,快速定位资料

文库首页搜索指引 立即搜索

相关学习资料