214 lines
8.8 KiB
HTML
214 lines
8.8 KiB
HTML
<div class="space-y-6" *ngIf="strategy">
|
|
<div class="flex flex-col md:flex-row md:justify-between md:items-start gap-4">
|
|
<!-- Strategy Overview Card -->
|
|
<mat-card class="flex-1 p-4">
|
|
<div class="flex items-start justify-between">
|
|
<div>
|
|
<h2 class="text-xl font-bold">{{strategy.name}}</h2>
|
|
<p class="text-gray-600 text-sm">{{strategy.description}}</p>
|
|
</div>
|
|
<div class="flex items-center gap-2">
|
|
<button mat-raised-button color="primary" class="mr-2" (click)="openBacktestDialog()">
|
|
Run Backtest
|
|
</button>
|
|
<span class="px-3 py-1 rounded-full text-xs font-semibold"
|
|
[style.background-color]="getStatusColor(strategy.status)"
|
|
style="color: white;">
|
|
{{strategy.status}}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
<div>
|
|
<h3 class="font-semibold text-sm text-gray-600">Type</h3>
|
|
<p>{{strategy.type}}</p>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-semibold text-sm text-gray-600">Created</h3>
|
|
<p>{{strategy.createdAt | date:'medium'}}</p>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-semibold text-sm text-gray-600">Last Updated</h3>
|
|
<p>{{strategy.updatedAt | date:'medium'}}</p>
|
|
</div>
|
|
<div>
|
|
<h3 class="font-semibold text-sm text-gray-600">Symbols</h3>
|
|
<div class="flex flex-wrap gap-1 mt-1">
|
|
<mat-chip *ngFor="let symbol of strategy.symbols">{{symbol}}</mat-chip>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</mat-card>
|
|
|
|
<!-- Performance Summary Card -->
|
|
<mat-card class="md:w-1/3 p-4">
|
|
<h3 class="text-lg font-bold mb-3">Performance</h3>
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div>
|
|
<p class="text-sm text-gray-600">Return</p>
|
|
<p class="text-xl font-semibold"
|
|
[ngClass]="{'text-green-600': performance.totalReturn >= 0, 'text-red-600': performance.totalReturn < 0}">
|
|
{{performance.totalReturn | percent:'1.2-2'}}
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-600">Win Rate</p>
|
|
<p class="text-xl font-semibold">{{performance.winRate | percent:'1.0-0'}}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-600">Sharpe Ratio</p>
|
|
<p class="text-xl font-semibold">{{performance.sharpeRatio | number:'1.2-2'}}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-600">Max Drawdown</p>
|
|
<p class="text-xl font-semibold text-red-600">{{performance.maxDrawdown | percent:'1.2-2'}}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-600">Total Trades</p>
|
|
<p class="text-xl font-semibold">{{performance.totalTrades}}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-sm text-gray-600">Sortino Ratio</p>
|
|
<p class="text-xl font-semibold">{{performance.sortinoRatio | number:'1.2-2'}}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<mat-divider class="my-4"></mat-divider>
|
|
|
|
<div class="flex justify-between mt-2">
|
|
<button mat-button color="primary" *ngIf="strategy.status !== 'ACTIVE'" (click)="activateStrategy()">
|
|
<mat-icon>play_arrow</mat-icon> Start
|
|
</button>
|
|
<button mat-button color="accent" *ngIf="strategy.status === 'ACTIVE'" (click)="pauseStrategy()">
|
|
<mat-icon>pause</mat-icon> Pause
|
|
</button>
|
|
<button mat-button color="warn" *ngIf="strategy.status === 'ACTIVE'" (click)="stopStrategy()">
|
|
<mat-icon>stop</mat-icon> Stop
|
|
</button>
|
|
<button mat-button (click)="openEditDialog()">
|
|
<mat-icon>edit</mat-icon> Edit
|
|
</button>
|
|
</div>
|
|
</mat-card>
|
|
</div>
|
|
|
|
<!-- Parameters Card -->
|
|
<mat-card class="p-4">
|
|
<h3 class="text-lg font-bold mb-3">Strategy Parameters</h3>
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div *ngFor="let param of strategy.parameters | keyvalue">
|
|
<p class="text-sm text-gray-600">{{param.key}}</p>
|
|
<p class="font-semibold">{{param.value}}</p>
|
|
</div>
|
|
</div>
|
|
</mat-card>
|
|
<!-- Backtest Results Section (only shown when a backtest has been run) -->
|
|
<div *ngIf="backtestResult" class="backtest-results space-y-6">
|
|
<h2 class="text-xl font-bold">Backtest Results</h2>
|
|
|
|
<!-- Performance Metrics Component -->
|
|
<app-performance-metrics [backtestResult]="backtestResult"></app-performance-metrics>
|
|
|
|
<!-- Equity Chart Component -->
|
|
<app-equity-chart [backtestResult]="backtestResult"></app-equity-chart>
|
|
|
|
<!-- Drawdown Chart Component -->
|
|
<app-drawdown-chart [backtestResult]="backtestResult"></app-drawdown-chart>
|
|
|
|
<!-- Trades Table Component -->
|
|
<app-trades-table [backtestResult]="backtestResult"></app-trades-table>
|
|
</div>
|
|
|
|
<!-- Tabs for Signals/Trades -->
|
|
<mat-card class="p-0">
|
|
<mat-tab-group>
|
|
<!-- Signals Tab -->
|
|
<mat-tab label="Recent Signals">
|
|
<div class="p-4">
|
|
<ng-container *ngIf="!isLoadingSignals; else loadingSignals">
|
|
<table class="min-w-full">
|
|
<thead>
|
|
<tr>
|
|
<th class="py-2 text-left">Time</th>
|
|
<th class="py-2 text-left">Symbol</th>
|
|
<th class="py-2 text-left">Action</th>
|
|
<th class="py-2 text-left">Price</th>
|
|
<th class="py-2 text-left">Quantity</th>
|
|
<th class="py-2 text-left">Confidence</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr *ngFor="let signal of signals">
|
|
<td class="py-2">{{signal.timestamp | date:'short'}}</td>
|
|
<td class="py-2">{{signal.symbol}}</td>
|
|
<td class="py-2">
|
|
<span class="px-2 py-1 rounded text-xs font-semibold"
|
|
[style.background-color]="getSignalColor(signal.action)"
|
|
style="color: white;">
|
|
{{signal.action}}
|
|
</span>
|
|
</td>
|
|
<td class="py-2">${{signal.price | number:'1.2-2'}}</td>
|
|
<td class="py-2">{{signal.quantity}}</td>
|
|
<td class="py-2">{{signal.confidence | percent:'1.0-0'}}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</ng-container>
|
|
<ng-template #loadingSignals>
|
|
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
|
</ng-template>
|
|
</div>
|
|
</mat-tab>
|
|
|
|
<!-- Trades Tab -->
|
|
<mat-tab label="Recent Trades">
|
|
<div class="p-4">
|
|
<ng-container *ngIf="!isLoadingTrades; else loadingTrades">
|
|
<table class="min-w-full">
|
|
<thead>
|
|
<tr>
|
|
<th class="py-2 text-left">Symbol</th>
|
|
<th class="py-2 text-left">Entry</th>
|
|
<th class="py-2 text-left">Exit</th>
|
|
<th class="py-2 text-left">Quantity</th>
|
|
<th class="py-2 text-left">P&L</th>
|
|
<th class="py-2 text-left">P&L %</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr *ngFor="let trade of trades">
|
|
<td class="py-2">{{trade.symbol}}</td>
|
|
<td class="py-2">
|
|
${{trade.entryPrice | number:'1.2-2'}} @ {{trade.entryTime | date:'short'}}
|
|
</td>
|
|
<td class="py-2">
|
|
${{trade.exitPrice | number:'1.2-2'}} @ {{trade.exitTime | date:'short'}}
|
|
</td>
|
|
<td class="py-2">{{trade.quantity}}</td>
|
|
<td class="py-2" [ngClass]="{'text-green-600': trade.pnl >= 0, 'text-red-600': trade.pnl < 0}">
|
|
${{trade.pnl | number:'1.2-2'}}
|
|
</td>
|
|
<td class="py-2" [ngClass]="{'text-green-600': trade.pnlPercent >= 0, 'text-red-600': trade.pnlPercent < 0}">
|
|
{{trade.pnlPercent | number:'1.2-2'}}%
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</ng-container>
|
|
<ng-template #loadingTrades>
|
|
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
|
</ng-template>
|
|
</div>
|
|
</mat-tab>
|
|
</mat-tab-group>
|
|
</mat-card>
|
|
</div>
|
|
|
|
<mat-card class="p-6 flex items-center" *ngIf="!strategy">
|
|
<div class="text-center text-gray-500 w-full">
|
|
<mat-icon style="font-size: 4rem; width: 4rem; height: 4rem;">psychology</mat-icon>
|
|
<p class="mb-4">No strategy selected</p>
|
|
</div>
|
|
</mat-card>
|