Jimin Huang commited on
Commit
9b3da36
1 Parent(s): b8b8f04

Change settings

Browse files
Files changed (1) hide show
  1. src/components/CompareChartE.vue +44 -16
src/components/CompareChartE.vue CHANGED
@@ -23,20 +23,32 @@ echarts.use([LineChart, GridComponent, LegendComponent, TooltipComponent, DataZo
23
 
24
  const ASSET_CUTOFF = {
25
  BTC: '2025-08-01',
26
- // ETH: '2025-08-15', // example if you add others later
27
  };
28
 
 
 
 
 
 
 
 
 
29
  export default defineComponent({
30
  name: 'CompareChartE',
31
  components: { VChart },
32
  props: {
33
  selected: { type: Array, default: () => [] },
34
- visible: { type: Boolean, default: true }
 
 
35
  },
36
  data(){ return { option: {} } },
37
  watch: {
38
  selected: { deep: true, handler(){ this.rebuild() } },
39
- visible(v){ if (v) this.$nextTick(() => this.rebuild()) }
 
 
40
  },
41
  mounted(){ this.$nextTick(() => this.rebuild()) },
42
  methods: {
@@ -72,7 +84,7 @@ export default defineComponent({
72
  groupKeyToSeq.set(`${agent}|${asset}|${model}`, { sel, seq: filtered })
73
  }
74
 
75
- // 2) Build series using (time,value) pairs => no misalignment
76
  const series = []
77
  const legend = []
78
  const assets = new Set()
@@ -89,7 +101,10 @@ export default defineComponent({
89
 
90
  const cfg = (STRATEGIES || []).find(s => s.id === sel.strategy) || { strategy: 'long_only', tradingMode: 'aggressive', fee: 0.0005, label: 'Selected' }
91
  const stratY = computeStrategyEquity(seq, 100000, cfg.fee, cfg.strategy, cfg.tradingMode) || []
92
- const points = seq.map((row, i) => [row.date, stratY[i]]) // << key change
 
 
 
93
 
94
  const name = `${agent} 路 ${sel.model} 路 ${cfg.label}`
95
  legend.push(name)
@@ -99,18 +114,22 @@ export default defineComponent({
99
  showSymbol: false,
100
  smooth: false,
101
  emphasis: { focus: 'series' },
102
- lineStyle: { width: 2 },
103
  areaStyle: { opacity: 0.06 },
104
  data: points
105
  })
106
  }
107
 
108
- // 3) Buy & Hold baseline per asset (also time/value points)
109
  for (const asset of assets) {
110
  const entry = [...groupKeyToSeq.values()].find(v => v.sel.asset === asset)
111
  if (!entry) continue
112
  const bhY = computeBuyHoldEquity(entry.seq, 100000) || []
113
- const bhPoints = entry.seq.map((row, i) => [row.date, bhY[i]])
 
 
 
 
114
  series.push({
115
  name: `${asset} 路 Buy&Hold`,
116
  type: 'line',
@@ -128,16 +147,25 @@ export default defineComponent({
128
  tooltip: {
129
  trigger: 'axis',
130
  axisPointer: { type: 'line' },
131
- valueFormatter: v => typeof v === 'number'
132
- ? v.toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
133
- : v
 
 
 
 
134
  },
135
  legend: { type: 'scroll', bottom: 8, icon: 'roundRect', itemGap: 10, data: legend },
136
- xAxis: { type: 'time' }, // << time axis = auto alignment
137
- yAxis: {
138
- type: 'value', scale: true,
139
- axisLabel: { formatter: v => v.toLocaleString(undefined, {style:'currency', currency:'USD', maximumFractionDigits:0 }) }
140
- },
 
 
 
 
 
141
  dataZoom: [{ type: 'inside', throttle: 50 }, { type: 'slider', height: 14, bottom: 36 }],
142
  series
143
  }
 
23
 
24
  const ASSET_CUTOFF = {
25
  BTC: '2025-08-01',
26
+ // ETH: '2025-08-15',
27
  };
28
 
29
+ // helper: convert [ [date, y], ... ] into % since first y
30
+ function toPct(points){
31
+ if (!Array.isArray(points) || !points.length) return points
32
+ const y0 = points[0][1]
33
+ if (typeof y0 !== 'number' || !isFinite(y0) || y0 === 0) return points
34
+ return points.map(([t, y]) => [t, ((y / y0) - 1) * 100])
35
+ }
36
+
37
  export default defineComponent({
38
  name: 'CompareChartE',
39
  components: { VChart },
40
  props: {
41
  selected: { type: Array, default: () => [] },
42
+ visible: { type: Boolean, default: true },
43
+ // NEW: $/% toggle
44
+ mode: { type: String, default: 'usd' } // 'usd' | 'pct'
45
  },
46
  data(){ return { option: {} } },
47
  watch: {
48
  selected: { deep: true, handler(){ this.rebuild() } },
49
+ visible(v){ if (v) this.$nextTick(() => this.rebuild()) },
50
+ // NEW: rebuild when the toggle changes
51
+ mode(){ this.rebuild() }
52
  },
53
  mounted(){ this.$nextTick(() => this.rebuild()) },
54
  methods: {
 
84
  groupKeyToSeq.set(`${agent}|${asset}|${model}`, { sel, seq: filtered })
85
  }
86
 
87
+ // 2) Build series using (time,value) pairs
88
  const series = []
89
  const legend = []
90
  const assets = new Set()
 
101
 
102
  const cfg = (STRATEGIES || []).find(s => s.id === sel.strategy) || { strategy: 'long_only', tradingMode: 'aggressive', fee: 0.0005, label: 'Selected' }
103
  const stratY = computeStrategyEquity(seq, 100000, cfg.fee, cfg.strategy, cfg.tradingMode) || []
104
+ let points = seq.map((row, i) => [row.date, stratY[i]])
105
+
106
+ // NEW: convert to % mode if requested
107
+ if (this.mode === 'pct') points = toPct(points)
108
 
109
  const name = `${agent} 路 ${sel.model} 路 ${cfg.label}`
110
  legend.push(name)
 
114
  showSymbol: false,
115
  smooth: false,
116
  emphasis: { focus: 'series' },
117
+ lineStyle: { width: 2, color: getStrategyColor(sel.strategy || '', false, idx) },
118
  areaStyle: { opacity: 0.06 },
119
  data: points
120
  })
121
  }
122
 
123
+ // 3) Buy & Hold baseline per asset
124
  for (const asset of assets) {
125
  const entry = [...groupKeyToSeq.values()].find(v => v.sel.asset === asset)
126
  if (!entry) continue
127
  const bhY = computeBuyHoldEquity(entry.seq, 100000) || []
128
+ let bhPoints = entry.seq.map((row, i) => [row.date, bhY[i]])
129
+
130
+ // NEW: % mode for baseline too
131
+ if (this.mode === 'pct') bhPoints = toPct(bhPoints)
132
+
133
  series.push({
134
  name: `${asset} 路 Buy&Hold`,
135
  type: 'line',
 
147
  tooltip: {
148
  trigger: 'axis',
149
  axisPointer: { type: 'line' },
150
+ // NEW: format per mode
151
+ valueFormatter: v => {
152
+ if (typeof v !== 'number') return v
153
+ return this.mode === 'pct'
154
+ ? `${v.toFixed(2)}%`
155
+ : v.toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
156
+ }
157
  },
158
  legend: { type: 'scroll', bottom: 8, icon: 'roundRect', itemGap: 10, data: legend },
159
+ xAxis: { type: 'time' },
160
+ yAxis: this.mode === 'pct'
161
+ ? {
162
+ type: 'value', scale: true,
163
+ axisLabel: { formatter: v => `${Number(v).toLocaleString(undefined, { maximumFractionDigits: 0 })}%` }
164
+ }
165
+ : {
166
+ type: 'value', scale: true,
167
+ axisLabel: { formatter: v => Number(v).toLocaleString(undefined, {style:'currency', currency:'USD', maximumFractionDigits:0 }) }
168
+ },
169
  dataZoom: [{ type: 'inside', throttle: 50 }, { type: 'slider', height: 14, bottom: 36 }],
170
  series
171
  }