linxus fs fixes
This commit is contained in:
parent
ac23b70146
commit
0b7846fe67
292 changed files with 41947 additions and 41947 deletions
|
|
@ -1,258 +1,258 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { BacktestResult } from '../../../services/strategy.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-performance-metrics',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatCardModule,
|
||||
MatGridListModule,
|
||||
MatDividerModule,
|
||||
MatTooltipModule
|
||||
],
|
||||
template: `
|
||||
<mat-card class="metrics-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Performance Metrics</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-group">
|
||||
<h3>Returns</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Total return over the backtest period">Total Return</div>
|
||||
<div class="metric-value" [ngClass]="getReturnClass(backtestResult?.totalReturn || 0)">
|
||||
{{formatPercent(backtestResult?.totalReturn || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Annualized return (adjusted for the backtest duration)">Annualized Return</div>
|
||||
<div class="metric-value" [ngClass]="getReturnClass(backtestResult?.annualizedReturn || 0)">
|
||||
{{formatPercent(backtestResult?.annualizedReturn || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Compound Annual Growth Rate">CAGR</div>
|
||||
<div class="metric-value" [ngClass]="getReturnClass(backtestResult?.cagr || 0)">
|
||||
{{formatPercent(backtestResult?.cagr || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="metric-group">
|
||||
<h3>Risk Metrics</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Maximum peak-to-valley drawdown">Max Drawdown</div>
|
||||
<div class="metric-value negative">
|
||||
{{formatPercent(backtestResult?.maxDrawdown || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Number of days in the worst drawdown">Max DD Duration</div>
|
||||
<div class="metric-value">
|
||||
{{formatDays(backtestResult?.maxDrawdownDuration || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Annualized standard deviation of returns">Volatility</div>
|
||||
<div class="metric-value">
|
||||
{{formatPercent(backtestResult?.volatility || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Square root of the sum of the squares of drawdowns">Ulcer Index</div>
|
||||
<div class="metric-value">
|
||||
{{(backtestResult?.ulcerIndex || 0).toFixed(4)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="metric-group">
|
||||
<h3>Risk-Adjusted Returns</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Excess return per unit of risk">Sharpe Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.sharpeRatio || 0)">
|
||||
{{(backtestResult?.sharpeRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Return per unit of downside risk">Sortino Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.sortinoRatio || 0)">
|
||||
{{(backtestResult?.sortinoRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Return per unit of max drawdown">Calmar Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.calmarRatio || 0)">
|
||||
{{(backtestResult?.calmarRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Probability-weighted ratio of gains vs. losses">Omega Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.omegaRatio || 0)">
|
||||
{{(backtestResult?.omegaRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="metric-group">
|
||||
<h3>Trade Statistics</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Total number of trades">Total Trades</div>
|
||||
<div class="metric-value">
|
||||
{{backtestResult?.totalTrades || 0}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Percentage of winning trades">Win Rate</div>
|
||||
<div class="metric-value" [ngClass]="getWinRateClass(backtestResult?.winRate || 0)">
|
||||
{{formatPercent(backtestResult?.winRate || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Average profit of winning trades">Avg Win</div>
|
||||
<div class="metric-value positive">
|
||||
{{formatPercent(backtestResult?.averageWinningTrade || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Average loss of losing trades">Avg Loss</div>
|
||||
<div class="metric-value negative">
|
||||
{{formatPercent(backtestResult?.averageLosingTrade || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Ratio of total gains to total losses">Profit Factor</div>
|
||||
<div class="metric-value" [ngClass]="getProfitFactorClass(backtestResult?.profitFactor || 0)">
|
||||
{{(backtestResult?.profitFactor || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
`,
|
||||
styles: `
|
||||
.metrics-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.metrics-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.metric-group {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.metric-group h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.metrics-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.metric {
|
||||
min-width: 120px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.metric-name {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.positive {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.negative {
|
||||
color: #F44336;
|
||||
}
|
||||
|
||||
.neutral {
|
||||
color: #FFA000;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 8px 0;
|
||||
}
|
||||
`
|
||||
})
|
||||
export class PerformanceMetricsComponent {
|
||||
@Input() backtestResult?: BacktestResult;
|
||||
|
||||
// Formatting helpers
|
||||
formatPercent(value: number): string {
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
style: 'percent',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(value);
|
||||
}
|
||||
|
||||
formatDays(days: number): string {
|
||||
return `${days} days`;
|
||||
}
|
||||
|
||||
// Conditional classes
|
||||
getReturnClass(value: number): string {
|
||||
if (value > 0) return 'positive';
|
||||
if (value < 0) return 'negative';
|
||||
return '';
|
||||
}
|
||||
|
||||
getRatioClass(value: number): string {
|
||||
if (value >= 1.5) return 'positive';
|
||||
if (value >= 1) return 'neutral';
|
||||
if (value < 0) return 'negative';
|
||||
return '';
|
||||
}
|
||||
|
||||
getWinRateClass(value: number): string {
|
||||
if (value >= 0.55) return 'positive';
|
||||
if (value >= 0.45) return 'neutral';
|
||||
return 'negative';
|
||||
}
|
||||
|
||||
getProfitFactorClass(value: number): string {
|
||||
if (value >= 1.5) return 'positive';
|
||||
if (value >= 1) return 'neutral';
|
||||
return 'negative';
|
||||
}
|
||||
}
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatGridListModule } from '@angular/material/grid-list';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { BacktestResult } from '../../../services/strategy.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-performance-metrics',
|
||||
standalone: true,
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatCardModule,
|
||||
MatGridListModule,
|
||||
MatDividerModule,
|
||||
MatTooltipModule
|
||||
],
|
||||
template: `
|
||||
<mat-card class="metrics-card">
|
||||
<mat-card-header>
|
||||
<mat-card-title>Performance Metrics</mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-group">
|
||||
<h3>Returns</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Total return over the backtest period">Total Return</div>
|
||||
<div class="metric-value" [ngClass]="getReturnClass(backtestResult?.totalReturn || 0)">
|
||||
{{formatPercent(backtestResult?.totalReturn || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Annualized return (adjusted for the backtest duration)">Annualized Return</div>
|
||||
<div class="metric-value" [ngClass]="getReturnClass(backtestResult?.annualizedReturn || 0)">
|
||||
{{formatPercent(backtestResult?.annualizedReturn || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Compound Annual Growth Rate">CAGR</div>
|
||||
<div class="metric-value" [ngClass]="getReturnClass(backtestResult?.cagr || 0)">
|
||||
{{formatPercent(backtestResult?.cagr || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="metric-group">
|
||||
<h3>Risk Metrics</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Maximum peak-to-valley drawdown">Max Drawdown</div>
|
||||
<div class="metric-value negative">
|
||||
{{formatPercent(backtestResult?.maxDrawdown || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Number of days in the worst drawdown">Max DD Duration</div>
|
||||
<div class="metric-value">
|
||||
{{formatDays(backtestResult?.maxDrawdownDuration || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Annualized standard deviation of returns">Volatility</div>
|
||||
<div class="metric-value">
|
||||
{{formatPercent(backtestResult?.volatility || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Square root of the sum of the squares of drawdowns">Ulcer Index</div>
|
||||
<div class="metric-value">
|
||||
{{(backtestResult?.ulcerIndex || 0).toFixed(4)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="metric-group">
|
||||
<h3>Risk-Adjusted Returns</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Excess return per unit of risk">Sharpe Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.sharpeRatio || 0)">
|
||||
{{(backtestResult?.sharpeRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Return per unit of downside risk">Sortino Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.sortinoRatio || 0)">
|
||||
{{(backtestResult?.sortinoRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Return per unit of max drawdown">Calmar Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.calmarRatio || 0)">
|
||||
{{(backtestResult?.calmarRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Probability-weighted ratio of gains vs. losses">Omega Ratio</div>
|
||||
<div class="metric-value" [ngClass]="getRatioClass(backtestResult?.omegaRatio || 0)">
|
||||
{{(backtestResult?.omegaRatio || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div class="metric-group">
|
||||
<h3>Trade Statistics</h3>
|
||||
<div class="metrics-row">
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Total number of trades">Total Trades</div>
|
||||
<div class="metric-value">
|
||||
{{backtestResult?.totalTrades || 0}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Percentage of winning trades">Win Rate</div>
|
||||
<div class="metric-value" [ngClass]="getWinRateClass(backtestResult?.winRate || 0)">
|
||||
{{formatPercent(backtestResult?.winRate || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Average profit of winning trades">Avg Win</div>
|
||||
<div class="metric-value positive">
|
||||
{{formatPercent(backtestResult?.averageWinningTrade || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Average loss of losing trades">Avg Loss</div>
|
||||
<div class="metric-value negative">
|
||||
{{formatPercent(backtestResult?.averageLosingTrade || 0)}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric">
|
||||
<div class="metric-name" matTooltip="Ratio of total gains to total losses">Profit Factor</div>
|
||||
<div class="metric-value" [ngClass]="getProfitFactorClass(backtestResult?.profitFactor || 0)">
|
||||
{{(backtestResult?.profitFactor || 0).toFixed(2)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
`,
|
||||
styles: `
|
||||
.metrics-card {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.metrics-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.metric-group {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.metric-group h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.metrics-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.metric {
|
||||
min-width: 120px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.metric-name {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.metric-value {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.positive {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.negative {
|
||||
color: #F44336;
|
||||
}
|
||||
|
||||
.neutral {
|
||||
color: #FFA000;
|
||||
}
|
||||
|
||||
mat-divider {
|
||||
margin: 8px 0;
|
||||
}
|
||||
`
|
||||
})
|
||||
export class PerformanceMetricsComponent {
|
||||
@Input() backtestResult?: BacktestResult;
|
||||
|
||||
// Formatting helpers
|
||||
formatPercent(value: number): string {
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
style: 'percent',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}).format(value);
|
||||
}
|
||||
|
||||
formatDays(days: number): string {
|
||||
return `${days} days`;
|
||||
}
|
||||
|
||||
// Conditional classes
|
||||
getReturnClass(value: number): string {
|
||||
if (value > 0) return 'positive';
|
||||
if (value < 0) return 'negative';
|
||||
return '';
|
||||
}
|
||||
|
||||
getRatioClass(value: number): string {
|
||||
if (value >= 1.5) return 'positive';
|
||||
if (value >= 1) return 'neutral';
|
||||
if (value < 0) return 'negative';
|
||||
return '';
|
||||
}
|
||||
|
||||
getWinRateClass(value: number): string {
|
||||
if (value >= 0.55) return 'positive';
|
||||
if (value >= 0.45) return 'neutral';
|
||||
return 'negative';
|
||||
}
|
||||
|
||||
getProfitFactorClass(value: number): string {
|
||||
if (value >= 1.5) return 'positive';
|
||||
if (value >= 1) return 'neutral';
|
||||
return 'negative';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue