- Added FastAPI backend with core API endpoints for strategies, backtests, and data management. - Introduced Vue 3 frontend with a dark theme, enabling users to run backtests, adjust parameters, and compare results. - Implemented Pydantic schemas for request/response validation and SQLAlchemy models for database interactions. - Enhanced project structure with dedicated modules for services, routers, and components. - Updated dependencies in `pyproject.toml` and `frontend/package.json` to include FastAPI, SQLAlchemy, and Vue-related packages. - Improved `.gitignore` to exclude unnecessary files and directories.
145 lines
4.0 KiB
Vue
145 lines
4.0 KiB
Vue
<script setup lang="ts">
|
|
import type { BacktestMetrics } from '@/api/types'
|
|
|
|
const props = defineProps<{
|
|
metrics: BacktestMetrics
|
|
leverage?: number
|
|
marketType?: string
|
|
}>()
|
|
|
|
function formatPercent(val: number): string {
|
|
return (val >= 0 ? '+' : '') + val.toFixed(2) + '%'
|
|
}
|
|
|
|
function formatNumber(val: number | null | undefined, decimals = 2): string {
|
|
if (val === null || val === undefined) return '-'
|
|
return val.toFixed(decimals)
|
|
}
|
|
|
|
function formatCurrency(val: number): string {
|
|
return '$' + val.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<!-- Total Return -->
|
|
<div class="card">
|
|
<div class="metric-label">Strategy Return</div>
|
|
<div
|
|
class="metric-value"
|
|
:class="metrics.total_return >= 0 ? 'profit' : 'loss'"
|
|
>
|
|
{{ formatPercent(metrics.total_return) }}
|
|
</div>
|
|
<div v-if="metrics.adjusted_return !== null && metrics.adjusted_return !== metrics.total_return" class="text-xs text-text-muted mt-1">
|
|
Adj: {{ formatPercent(metrics.adjusted_return) }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Benchmark Return -->
|
|
<div class="card">
|
|
<div class="metric-label">Benchmark (B&H)</div>
|
|
<div
|
|
class="metric-value"
|
|
:class="metrics.benchmark_return >= 0 ? 'profit' : 'loss'"
|
|
>
|
|
{{ formatPercent(metrics.benchmark_return) }}
|
|
</div>
|
|
<div class="text-xs text-text-muted mt-1">
|
|
Market change
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Alpha -->
|
|
<div class="card">
|
|
<div class="metric-label">Alpha</div>
|
|
<div
|
|
class="metric-value"
|
|
:class="metrics.alpha >= 0 ? 'profit' : 'loss'"
|
|
>
|
|
{{ formatPercent(metrics.alpha) }}
|
|
</div>
|
|
<div class="text-xs text-text-muted mt-1">
|
|
vs Buy & Hold
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sharpe Ratio -->
|
|
<div class="card">
|
|
<div class="metric-label">Sharpe Ratio</div>
|
|
<div
|
|
class="metric-value"
|
|
:class="metrics.sharpe_ratio >= 1 ? 'profit' : metrics.sharpe_ratio < 0 ? 'loss' : ''"
|
|
>
|
|
{{ formatNumber(metrics.sharpe_ratio) }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Max Drawdown -->
|
|
<div class="card">
|
|
<div class="metric-label">Max Drawdown</div>
|
|
<div class="metric-value loss">
|
|
{{ formatPercent(metrics.max_drawdown) }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Win Rate -->
|
|
<div class="card">
|
|
<div class="metric-label">Win Rate</div>
|
|
<div
|
|
class="metric-value"
|
|
:class="metrics.win_rate >= 50 ? 'profit' : 'loss'"
|
|
>
|
|
{{ formatNumber(metrics.win_rate, 1) }}%
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Total Trades -->
|
|
<div class="card">
|
|
<div class="metric-label">Total Trades</div>
|
|
<div class="metric-value">
|
|
{{ metrics.total_trades }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Profit Factor -->
|
|
<div class="card">
|
|
<div class="metric-label">Profit Factor</div>
|
|
<div
|
|
class="metric-value"
|
|
:class="(metrics.profit_factor || 0) >= 1 ? 'profit' : 'loss'"
|
|
>
|
|
{{ formatNumber(metrics.profit_factor) }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Total Fees -->
|
|
<div class="card">
|
|
<div class="metric-label">Total Fees</div>
|
|
<div class="metric-value text-warning">
|
|
{{ formatCurrency(metrics.total_fees) }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Funding (perpetual only) -->
|
|
<div v-if="marketType === 'perpetual'" class="card">
|
|
<div class="metric-label">Funding Paid</div>
|
|
<div class="metric-value text-warning">
|
|
{{ formatCurrency(metrics.total_funding) }}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Liquidations (if any) -->
|
|
<div v-if="metrics.liquidation_count > 0" class="card">
|
|
<div class="metric-label">Liquidations</div>
|
|
<div class="metric-value loss">
|
|
{{ metrics.liquidation_count }}
|
|
</div>
|
|
<div class="text-xs text-text-muted mt-1">
|
|
Lost: {{ formatCurrency(metrics.liquidation_loss) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|