Switch demo trading to 5m short-term swing setups (plan 3.1)
- The model now submits a pending setup (direction, zone, confirm price, validity); the executor enters at market once a 5m close confirms a dip into support or a rejection from resistance, and cancels the setup when the zone breaks, the trigger is missed or the stop is too far - Stop beyond the confirmation extreme by 0.5 x ATR14(5m), skipped above 1%; fixed take-profit ladders from the fill price (long 60/30/10 at +0.5/0.75/1%, short 80/20 at -0.5/0.75%); 4h time stop - While holding, the model may only keep or exit - Drop the long-term angle from the program, API, tables and page
This commit is contained in:
1 parent
1fcf41952c
commit
7efa2eb68b
12 files changed
+696
-746
No files matched your search
+44
-33
@@ -1,10 +1,6 @@
|
||||
import type { Effort } from "@/apis/settings"
|
||||
import { http } from "@/http"
|
||||
|
||||
export type Angle = "short" | "long"
|
||||
|
||||
export const ANGLE_LABELS: Record<Angle, string> = { short: "短线(24h 内平仓)", long: "长线(12–48h 平仓)" }
|
||||
|
||||
/** 以下数值字段都是币安返回的十进制字符串,避免浮点误差 */
|
||||
export interface SnapshotPosition {
|
||||
symbol: string
|
||||
@@ -73,7 +69,6 @@ export interface TradingStatus {
|
||||
|
||||
export interface TradingSymbol {
|
||||
symbol: string
|
||||
angle: Angle
|
||||
added_at: string
|
||||
analysis_requested_at: string | null
|
||||
analyzing: boolean
|
||||
@@ -128,12 +123,8 @@ export function listSymbols(): Promise<TradingSymbol[]> {
|
||||
return http.get("/trading/symbols")
|
||||
}
|
||||
|
||||
export function addSymbol(symbol: string, angle: Angle): Promise<void> {
|
||||
return http.post("/trading/symbols", { symbol, angle })
|
||||
}
|
||||
|
||||
export function patchSymbol(symbol: string, angle: Angle): Promise<void> {
|
||||
return http.patch(`/trading/symbols/${symbol}`, { angle })
|
||||
export function addSymbol(symbol: string): Promise<void> {
|
||||
return http.post("/trading/symbols", { symbol })
|
||||
}
|
||||
|
||||
export function deleteSymbol(symbol: string): Promise<void> {
|
||||
@@ -147,7 +138,7 @@ export function listEvents(params: { symbol?: string, before?: number, limit?: n
|
||||
export interface PlanCondition {
|
||||
direction: "above" | "below"
|
||||
price: string
|
||||
timeframe: "mark" | "1m" | "15m" | "1h" | "4h"
|
||||
timeframe: "mark" | "1m" | "5m" | "15m" | "1h" | "4h"
|
||||
basis: string
|
||||
}
|
||||
|
||||
@@ -160,42 +151,39 @@ export interface TradeDecision {
|
||||
reevaluate: PlanCondition[]
|
||||
direction: "long" | "short" | null
|
||||
confidence: "high" | "medium" | "low" | null
|
||||
entries: { price: string, ratio: string, basis: string }[] | null
|
||||
stop: string | null
|
||||
stop_basis: string | null
|
||||
take_profits: { price: string, basis: string }[] | null
|
||||
entry_valid_hours: string | null
|
||||
max_hold_hours: string | null
|
||||
invalidation: PlanCondition | null
|
||||
/** 待确认入场;计划 3.1 之前的分析没有这个字段 */
|
||||
setup?: { zone_low: string, zone_high: string, confirm_price: string, basis: string } | null
|
||||
valid_hours?: string | null
|
||||
}
|
||||
|
||||
/** 程序按交易资金算出的数量和风险 */
|
||||
export interface Sizing {
|
||||
direction: "long" | "short"
|
||||
entries: { price: string, ratio: string, quantity: string, notional: string }[]
|
||||
/** 程序按止损和交易资金算出的数量与风险 */
|
||||
export interface EntrySizing {
|
||||
price: string
|
||||
stop: string
|
||||
take_profits: { price: string, ratio: string, quantity: string }[]
|
||||
average_price: string
|
||||
stop_pct: string
|
||||
quantity: string
|
||||
notional: string
|
||||
capital: string
|
||||
leverage: string
|
||||
risk_amount: string
|
||||
risk_at_stop: string
|
||||
risk_pct: string
|
||||
capped_by_leverage: boolean
|
||||
reward_risk: string
|
||||
reward_risk_first_only: string
|
||||
/** 采纳前核对用:提交时的持仓数量 */
|
||||
}
|
||||
|
||||
export interface Sizing {
|
||||
direction: "long" | "short"
|
||||
setup: { zone_low: string, zone_high: string, confirm_price: string }
|
||||
/** 提交时按确认价入场、止损放在区间远端外估算 */
|
||||
estimate: EntrySizing
|
||||
atr: string
|
||||
position_qty: string
|
||||
/** 持仓中调整的计划:不加仓 */
|
||||
managed: boolean
|
||||
/** 5m 确认后由执行器写入;有它表示已触发 */
|
||||
entry?: EntrySizing & { triggered_at: string, bar_close: string, extreme: string, atr: string }
|
||||
}
|
||||
|
||||
export interface Analysis {
|
||||
id: number
|
||||
symbol: string
|
||||
angle: Angle
|
||||
reasons: string[]
|
||||
dry_run: boolean
|
||||
status: "running" | "done" | "failed"
|
||||
@@ -232,7 +220,7 @@ export type PlanStatus = "proposed" | "pending" | "open" | "closing" | "closed"
|
||||
|
||||
export const PLAN_STATUS_LABELS: Record<PlanStatus, string> = {
|
||||
proposed: "待采纳",
|
||||
pending: "挂单中",
|
||||
pending: "等待确认",
|
||||
open: "持仓中",
|
||||
closing: "平仓中",
|
||||
closed: "已结束",
|
||||
@@ -259,6 +247,29 @@ export interface OrderRow {
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export const CLOSE_REASON_LABELS: Record<string, string> = {
|
||||
stop: "止损",
|
||||
take_profit: "止盈",
|
||||
time: "到达持仓时限",
|
||||
exit: "模型决定结束",
|
||||
external: "外部平仓",
|
||||
stop_failed: "止损挂单失败",
|
||||
close: "市价平仓",
|
||||
replaced: "被新计划替换",
|
||||
expired: "到期未触发",
|
||||
stopped: "已停止交易",
|
||||
broken: "区间被突破",
|
||||
missed: "错过确认",
|
||||
skipped: "止损过远,放弃入场",
|
||||
entry_failed: "入场失败"
|
||||
}
|
||||
|
||||
/** 止盈阶梯(与后端 plan.TAKE_PROFIT_STEPS 一致):[距成交均价的涨跌幅, 平仓比例] */
|
||||
export const TAKE_PROFIT_STEPS: Record<"long" | "short", [number, number][]> = {
|
||||
long: [[0.005, 0.6], [0.0075, 0.3], [0.01, 0.1]],
|
||||
short: [[0.005, 0.8], [0.0075, 0.2]]
|
||||
}
|
||||
|
||||
export function getSymbolPlan(symbol: string): Promise<{ plan: Analysis | null, orders: OrderRow[] }> {
|
||||
return http.get(`/trading/symbols/${symbol}/plan`)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Angle, SymbolOption } from "@/apis/trading"
|
||||
import { addSymbol, ANGLE_LABELS, listSymbolOptions } from "@/apis/trading"
|
||||
import type { SymbolOption } from "@/apis/trading"
|
||||
import { addSymbol, listSymbolOptions } from "@/apis/trading"
|
||||
|
||||
const emit = defineEmits<{ added: [symbol: string] }>()
|
||||
const visible = defineModel<boolean>({ required: true })
|
||||
|
||||
const symbol = ref("")
|
||||
const angle = ref<Angle>("long")
|
||||
const symbolOptions = ref<SymbolOption[]>([])
|
||||
const loading = ref(false)
|
||||
const submitting = ref(false)
|
||||
@@ -28,7 +27,7 @@ watch(visible, async (open) => {
|
||||
async function submit() {
|
||||
submitting.value = true
|
||||
try {
|
||||
await addSymbol(symbol.value, angle.value)
|
||||
await addSymbol(symbol.value)
|
||||
ElMessage.success(`已加入 ${symbol.value}`)
|
||||
emit("added", symbol.value)
|
||||
visible.value = false
|
||||
@@ -50,13 +49,6 @@ async function submit() {
|
||||
只列出模拟盘和实盘都在交易的加密货币 USDT 永续合约
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="角度">
|
||||
<el-radio-group v-model="angle">
|
||||
<el-radio v-for="(label, value) in ANGLE_LABELS" :key="value" :value="value">
|
||||
{{ label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Analysis, OrderRow, PlanCondition, TradingSymbol } from "@/apis/trading"
|
||||
import { ANGLE_LABELS, PLAN_STATUS_LABELS } from "@/apis/trading"
|
||||
import { CLOSE_REASON_LABELS, PLAN_STATUS_LABELS, TAKE_PROFIT_STEPS } from "@/apis/trading"
|
||||
import { formatTime } from "@/utils/text"
|
||||
|
||||
/** analysis:执行中的计划,没有时为最近一次分析;latest:最近一次分析(与 analysis 不同时另行提示) */
|
||||
@@ -9,7 +9,8 @@ const emit = defineEmits<{ analyze: [], detail: [id: number] }>()
|
||||
|
||||
const ACTION_LABELS = { plan: "新计划", keep: "维持当前计划", exit: "结束当前计划", wait: "观望" } as const
|
||||
const CONFIDENCE_LABELS = { high: "高", medium: "中", low: "低" } as const
|
||||
const TIMEFRAME_LABELS = { "mark": "标记价触及", "1m": "1m 收盘", "15m": "15m 收盘", "1h": "1h 收盘", "4h": "4h 收盘" } as const
|
||||
const TIMEFRAME_LABELS = { "mark": "标记价触及", "1m": "1m 收盘", "5m": "5m 收盘", "15m": "15m 收盘", "1h": "1h 收盘", "4h": "4h 收盘" } as const
|
||||
const ACTIVE_ORDER_STATUSES = ["submitting", "new", "partially_filled"]
|
||||
|
||||
const now = ref(Date.now())
|
||||
const ticker = setInterval(() => now.value = Date.now(), 1000)
|
||||
@@ -38,15 +39,26 @@ function condition(c: PlanCondition) {
|
||||
return `${TIMEFRAME_LABELS[c.timeframe]}${c.direction === "above" ? "高于" : "低于"} ${c.price}`
|
||||
}
|
||||
|
||||
/** 失效后的应急动作:短线立即市价平仓,长线等 4h 收盘后请模型复核 */
|
||||
const invalidationAction = computed(() => props.analysis?.angle === "short" ? "立即市价平仓" : "请模型复核")
|
||||
const long = computed(() => sizing.value?.direction === "long")
|
||||
const entryRow = computed(() => props.orders.find(o => o.purpose === "entry" && Number(o.filled_qty) > 0))
|
||||
/** 交易所上生效的止损:止盈 1 后会移到保本价 */
|
||||
const currentStop = computed(() => props.orders.filter(o => o.purpose === "stop" && ACTIVE_ORDER_STATUSES.includes(o.status)).at(-1)?.trigger_price)
|
||||
const ladder = computed(() => sizing.value?.entry
|
||||
? TAKE_PROFIT_STEPS[sizing.value.direction].map(([pct, ratio], leg) => ({
|
||||
leg,
|
||||
move: `${long.value ? "+" : "−"}${pct * 100}%`,
|
||||
ratio: `${Math.round(ratio * 100)}%`,
|
||||
price: props.orders.filter(o => o.purpose === "tp" && o.leg === leg).at(-1)?.price ?? "-",
|
||||
filled: filled("tp", leg)
|
||||
}))
|
||||
: [])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="border border-[var(--el-border-color)] rounded border-solid p-3">
|
||||
<div class="mb-2 flex items-center gap-2">
|
||||
<span class="font-bold">{{ symbol.symbol }}</span>
|
||||
<span class="text-xs text-[var(--el-text-color-secondary)]">{{ ANGLE_LABELS[symbol.angle] }}</span>
|
||||
<span class="text-xs text-[var(--el-text-color-secondary)]">短线做波动(5m 确认入场,最长持仓 4 小时)</span>
|
||||
<div class="flex-1" />
|
||||
<el-button v-if="analysis && analysis.status !== 'running'" link type="primary" @click="emit('detail', analysis.id)">
|
||||
查看完整分析
|
||||
@@ -104,79 +116,58 @@ const invalidationAction = computed(() => props.analysis?.angle === "short" ? "
|
||||
</el-link>
|
||||
</div>
|
||||
<div v-if="analysis.valid_until || analysis.close_deadline" class="flex flex-wrap gap-x-6">
|
||||
<span v-if="analysis.plan_status === 'pending' && analysis.valid_until"><span class="label">入场单有效至</span>{{ formatTime(analysis.valid_until, "MM-DD HH:mm") }}(剩 {{ countdown(analysis.valid_until) }})</span>
|
||||
<span v-if="analysis.first_fill_at"><span class="label">首档成交</span>{{ formatTime(analysis.first_fill_at, "MM-DD HH:mm") }}</span>
|
||||
<span v-if="analysis.plan_status === 'pending' && analysis.valid_until && !sizing?.entry"><span class="label">等待确认至</span>{{ formatTime(analysis.valid_until, "MM-DD HH:mm") }}(剩 {{ countdown(analysis.valid_until) }})</span>
|
||||
<span v-if="analysis.first_fill_at"><span class="label">入场</span>{{ formatTime(analysis.first_fill_at, "MM-DD HH:mm") }}</span>
|
||||
<span v-if="analysis.close_deadline"><span class="label">最晚平仓</span>{{ formatTime(analysis.close_deadline, "MM-DD HH:mm") }}(剩 {{ countdown(analysis.close_deadline) }})</span>
|
||||
</div>
|
||||
<div v-if="analysis.result">
|
||||
<span class="label">结果</span>{{ analysis.close_reason }},净盈亏 {{ analysis.result.net }} USDT(手续费 {{ analysis.result.commission }})
|
||||
<span class="label">结果</span>{{ CLOSE_REASON_LABELS[analysis.close_reason ?? ""] ?? analysis.close_reason }},净盈亏 {{ analysis.result.net }} USDT(手续费 {{ analysis.result.commission }})
|
||||
</div>
|
||||
<div><span class="label">为什么</span>{{ decision.reasons }}</div>
|
||||
|
||||
<div v-if="sizing?.managed" class="text-xs text-[var(--el-text-color-secondary)]">
|
||||
持仓中调整的计划:不加仓,止盈按当前持仓数量拆分
|
||||
</div>
|
||||
<template v-if="decision.action === 'plan' && sizing">
|
||||
<el-table v-if="sizing.entries.length" :data="sizing.entries" border size="small">
|
||||
<el-table-column label="入场档位" min-width="110">
|
||||
<template #default="{ $index }">
|
||||
第 {{ $index + 1 }} 档
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="挂单价" min-width="100" />
|
||||
<el-table-column label="比例" width="80">
|
||||
<template #default="{ row }">
|
||||
{{ Math.round(Number(row.ratio) * 100) }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quantity" label="数量" min-width="90" />
|
||||
<el-table-column prop="notional" label="名义 USDT" min-width="100" />
|
||||
<el-table-column label="已成交" min-width="80">
|
||||
<template #default="{ $index }">
|
||||
{{ filled("entry", $index) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="依据" min-width="200">
|
||||
<template #default="{ $index }">
|
||||
{{ decision.entries?.[$index]?.basis }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-table :data="sizing.take_profits" border size="small">
|
||||
<el-table-column label="分批止盈" min-width="110">
|
||||
<template #default="{ $index }">
|
||||
止盈 {{ $index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="price" label="价格" min-width="100" />
|
||||
<el-table-column label="平仓比例" width="80">
|
||||
<template #default="{ row }">
|
||||
{{ Math.round(Number(row.ratio) * 100) }}%
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="quantity" label="数量" min-width="90" />
|
||||
<el-table-column label="已成交" min-width="80">
|
||||
<template #default="{ $index }">
|
||||
{{ filled("tp", $index) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="依据" min-width="300">
|
||||
<template #default="{ $index }">
|
||||
{{ decision.take_profits?.[$index]?.basis }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template v-if="decision.action === 'plan' && decision.setup && sizing?.setup">
|
||||
<div class="grid grid-cols-2 gap-x-6 gap-y-1">
|
||||
<div><span class="label">止损</span>{{ sizing.stop }}(交易所挂单,标记价触发)· {{ decision.stop_basis }}</div>
|
||||
<div>
|
||||
<span class="label">失效条件</span>{{ decision.invalidation ? condition(decision.invalidation) : "-" }}
|
||||
→ {{ invalidationAction }} · {{ decision.invalidation?.basis }}
|
||||
<span class="label">{{ long ? "支撑区" : "压力区" }}</span>{{ sizing.setup.zone_low }} – {{ sizing.setup.zone_high }} · {{ decision.setup.basis }}
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">确认</span>5m {{ long ? "最低价进区后收盘 ≥" : "最高价进区后收盘 ≤" }} {{ sizing.setup.confirm_price }} → 市价{{ long ? "做多" : "做空" }};
|
||||
先有收盘{{ long ? "低于" : "高于" }} {{ long ? sizing.setup.zone_low : sizing.setup.zone_high }} 则撤销
|
||||
</div>
|
||||
<div v-if="!sizing.entry">
|
||||
<span class="label">预估</span>按确认价入场:止损 {{ sizing.estimate.stop }}({{ sizing.estimate.stop_pct }}%),数量 {{ sizing.estimate.quantity }},止损亏损 {{ sizing.estimate.risk_at_stop }} USDT
|
||||
</div>
|
||||
<div v-if="!sizing.entry">
|
||||
<span class="label">有效期</span>{{ decision.valid_hours }} 小时;止损按触发时的极值外 0.5×ATR(5m) 计算,超过 1% 放弃入场
|
||||
</div>
|
||||
<div><span class="label">均价 / 数量</span>{{ sizing.average_price }} / {{ sizing.quantity }}(名义 {{ sizing.notional }} USDT,{{ sizing.leverage }} 倍交易资金)</div>
|
||||
<div><span class="label">止损亏损</span>{{ sizing.risk_at_stop }} USDT(交易资金的 {{ sizing.risk_pct }}%){{ sizing.capped_by_leverage ? ",受 3 倍上限限制" : "" }}</div>
|
||||
<div><span class="label">盈亏比</span>全部成交 {{ sizing.reward_risk }},仅首档 {{ sizing.reward_risk_first_only }}</div>
|
||||
<div><span class="label">时效</span>挂单 {{ decision.entry_valid_hours }} 小时内有效,首档成交后最长持仓 {{ decision.max_hold_hours }} 小时</div>
|
||||
</div>
|
||||
<template v-if="sizing.entry">
|
||||
<div class="grid grid-cols-2 gap-x-6 gap-y-1">
|
||||
<div>
|
||||
<span class="label">触发</span>{{ formatTime(sizing.entry.triggered_at, "MM-DD HH:mm:ss") }},5m 收盘 {{ sizing.entry.bar_close }},{{ long ? "最低" : "最高" }} {{ sizing.entry.extreme }},ATR {{ sizing.entry.atr }}
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">入场</span>市价 {{ sizing.entry.quantity }},成交均价 {{ entryRow?.avg_price ?? "待成交" }}(名义 {{ sizing.entry.notional }} USDT,{{ sizing.entry.leverage }} 倍交易资金)
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">止损</span>{{ currentStop ?? sizing.entry.stop }}(初始 {{ sizing.entry.stop }},{{ sizing.entry.stop_pct }}%;止盈 1 后移到保本价)
|
||||
</div>
|
||||
<div>
|
||||
<span class="label">止损亏损</span>{{ sizing.entry.risk_at_stop }} USDT(交易资金的 {{ sizing.entry.risk_pct }}%){{ sizing.entry.capped_by_leverage ? ",受 3 倍上限限制" : "" }}
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="ladder" border size="small">
|
||||
<el-table-column label="分批止盈" min-width="90">
|
||||
<template #default="{ row }">
|
||||
止盈 {{ row.leg + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="move" label="距成交均价" min-width="90" />
|
||||
<el-table-column prop="ratio" label="平仓比例" min-width="80" />
|
||||
<el-table-column prop="price" label="价格" min-width="100" />
|
||||
<el-table-column prop="filled" label="已成交" min-width="80" />
|
||||
</el-table>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<div v-if="decision.reevaluate.length">
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Effort, Provider } from "@/apis/settings"
|
||||
import type { Analysis, Angle, OrderRow, SnapshotPosition, TradingEvent, TradingStatus, TradingSymbol } from "@/apis/trading"
|
||||
import type { Analysis, OrderRow, SnapshotPosition, TradingEvent, TradingStatus, TradingSymbol } from "@/apis/trading"
|
||||
import { EFFORTS, listProviders } from "@/apis/settings"
|
||||
import { ANGLE_LABELS, deleteSymbol, getStatus, getSymbolPlan, isOwnOrder, listAnalyses, listEvents, listSymbols, patchConfig, patchSymbol, requestAnalysis, startTrading, stopTrading } from "@/apis/trading"
|
||||
import { deleteSymbol, getStatus, getSymbolPlan, isOwnOrder, listAnalyses, listEvents, listSymbols, patchConfig, requestAnalysis, startTrading, stopTrading } from "@/apis/trading"
|
||||
import { usePersisted } from "@/utils/storage"
|
||||
import { formatTime } from "@/utils/text"
|
||||
import AddSymbolDialog from "./components/AddSymbolDialog.vue"
|
||||
@@ -11,7 +11,6 @@ import PlanCard from "./components/PlanCard.vue"
|
||||
|
||||
const STATUS_REFRESH_MS = 3000
|
||||
const EVENTS_PAGE = 50
|
||||
const SHORT_ANGLE_LABELS: Record<Angle, string> = { short: "短线", long: "长线" }
|
||||
const LEVEL_TYPES = { info: "primary", warn: "warning", error: "danger" } as const
|
||||
|
||||
const status = ref<TradingStatus>()
|
||||
@@ -88,7 +87,7 @@ function symbolState(s: TradingSymbol) {
|
||||
if (positions.value.some(p => p.symbol === s.symbol))
|
||||
return { label: "持仓中", type: "success" } as const
|
||||
if (s.plan_status === "pending")
|
||||
return { label: "挂单中", type: "primary" } as const
|
||||
return { label: "等待确认", type: "primary" } as const
|
||||
return { label: "空仓", type: "info" } as const
|
||||
}
|
||||
|
||||
@@ -171,7 +170,7 @@ watch(selected, () => {
|
||||
async function toggleRunning() {
|
||||
if (status.value!.running) {
|
||||
await ElMessageBox.confirm(
|
||||
"停止后不再做新的分析,并撤销未成交的入场单。已有持仓保留,止损、止盈、到期平仓、短线失效平仓等程序规则继续执行。",
|
||||
"停止后不再做新的分析,并撤销还在等待确认的计划。已有持仓保留,止损、止盈、到期平仓等程序规则继续执行。",
|
||||
"停止行情交易",
|
||||
{ type: "warning", confirmButtonText: "停止" }
|
||||
)
|
||||
@@ -215,13 +214,6 @@ async function changeEffort(effort: Effort | null) {
|
||||
status.value = await patchConfig({ reasoning_effort: effort })
|
||||
}
|
||||
|
||||
async function switchAngle(s: TradingSymbol) {
|
||||
const angle: Angle = s.angle === "short" ? "long" : "short"
|
||||
await ElMessageBox.confirm(`把 ${s.symbol} 从${SHORT_ANGLE_LABELS[s.angle]}改为${SHORT_ANGLE_LABELS[angle]}?`, "切换角度")
|
||||
await patchSymbol(s.symbol, angle)
|
||||
await Promise.all([refresh(), refreshEvents()])
|
||||
}
|
||||
|
||||
async function remove(s: TradingSymbol) {
|
||||
await ElMessageBox.confirm(`把 ${s.symbol} 移出交易列表?历史分析和时间线会保留。`, "删除确认", { type: "warning" })
|
||||
await deleteSymbol(s.symbol)
|
||||
@@ -397,12 +389,10 @@ onBeforeUnmount(() => clearInterval(timer))
|
||||
{{ symbolState(s).label }}
|
||||
</el-tag>
|
||||
</div>
|
||||
<div class="mt-1 flex items-center justify-between text-xs text-[var(--el-text-color-secondary)]">
|
||||
<span>{{ ANGLE_LABELS[s.angle] }}</span>
|
||||
<span>
|
||||
<el-link type="primary" underline="never" class="text-xs!" @click.stop="switchAngle(s)">切换角度</el-link>
|
||||
<el-link type="danger" underline="never" class="ml-2 text-xs!" @click.stop="remove(s)">删除</el-link>
|
||||
</span>
|
||||
<div class="mt-1 flex justify-end text-xs">
|
||||
<el-link type="danger" underline="never" class="text-xs!" @click.stop="remove(s)">
|
||||
删除
|
||||
</el-link>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-if="!symbols.length" description="还没有交易币种" :image-size="60" />
|
||||
|
||||
Reference in new issue
Block a user