Skip to content

Commit d02adfb

Browse files
committed
Add Paper Trading Journal with analytics (#65)
- PaperTrade model extending ContextualEntry - PaperTradeService with CRUD, close trade, and analytics - Summary stats (win rate, P&L) - Stats by pattern tag - Stats by gamma regime - Export as JSON/CSV - PaperTrading.razor page with: - Open/Closed trade tabs - Analytics dashboard - New trade modal with direction, price, targets - Close trade modal with P&L preview - Added to home page with green chart-line icon
1 parent 0753ee4 commit d02adfb

7 files changed

Lines changed: 1542 additions & 0 deletions

File tree

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
namespace GexVisor.UI.Models;
2+
3+
/// <summary>
4+
/// Represents a hypothetical paper trade for tracking GEX-based trading strategies.
5+
/// </summary>
6+
public record PaperTrade : ContextualEntry
7+
{
8+
/// <summary>Trade direction: "Long" or "Short".</summary>
9+
public required string Direction { get; init; }
10+
11+
/// <summary>Entry price for the trade.</summary>
12+
public required decimal EntryPrice { get; init; }
13+
14+
/// <summary>Optional target price for profit taking.</summary>
15+
public decimal? TargetPrice { get; init; }
16+
17+
/// <summary>Optional stop loss price.</summary>
18+
public decimal? StopLoss { get; init; }
19+
20+
/// <summary>Notes about the trade setup or reasoning.</summary>
21+
public string? Notes { get; init; }
22+
23+
// Exit fields
24+
/// <summary>Date when the trade was closed.</summary>
25+
public DateTime? ExitDate { get; init; }
26+
27+
/// <summary>Exit price when the trade was closed.</summary>
28+
public decimal? ExitPrice { get; init; }
29+
30+
/// <summary>Reason for exit: "Target", "Stop", "Manual", "Time".</summary>
31+
public string? ExitReason { get; init; }
32+
33+
// Computed properties
34+
/// <summary>Whether the trade is still open.</summary>
35+
public bool IsOpen => ExitDate == null;
36+
37+
/// <summary>P&L in price points (null if trade is open).</summary>
38+
public decimal? PnLPoints => ExitPrice.HasValue
39+
? (ExitPrice.Value - EntryPrice) * (Direction == "Long" ? 1 : -1)
40+
: null;
41+
42+
/// <summary>P&L as a percentage (null if trade is open).</summary>
43+
public decimal? PnLPercent => PnLPoints.HasValue && EntryPrice != 0
44+
? PnLPoints.Value / EntryPrice * 100
45+
: null;
46+
47+
/// <summary>Whether the trade was profitable.</summary>
48+
public bool? IsWin => PnLPoints.HasValue ? PnLPoints.Value > 0 : null;
49+
50+
/// <summary>Current unrealized P&L based on a given current price.</summary>
51+
public decimal GetUnrealizedPnL(decimal currentPrice)
52+
{
53+
return (currentPrice - EntryPrice) * (Direction == "Long" ? 1 : -1);
54+
}
55+
56+
/// <summary>Current unrealized P&L percentage based on a given current price.</summary>
57+
public decimal GetUnrealizedPnLPercent(decimal currentPrice)
58+
{
59+
return EntryPrice != 0 ? GetUnrealizedPnL(currentPrice) / EntryPrice * 100 : 0;
60+
}
61+
}
62+
63+
/// <summary>
64+
/// Direction constants for paper trades.
65+
/// </summary>
66+
public static class TradeDirection
67+
{
68+
public const string Long = "Long";
69+
public const string Short = "Short";
70+
}
71+
72+
/// <summary>
73+
/// Exit reason constants for paper trades.
74+
/// </summary>
75+
public static class ExitReason
76+
{
77+
public const string Target = "Target";
78+
public const string Stop = "Stop";
79+
public const string Manual = "Manual";
80+
public const string Time = "Time";
81+
}

src/GexVisor.UI/Pages/Index.razor

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,19 @@
4747
</div>
4848
</div>
4949
</a>
50+
51+
<a href="/trading" class="app-card">
52+
<div class="app-icon trading">
53+
<i class="fas fa-chart-line"></i>
54+
</div>
55+
<div class="app-info">
56+
<h2>Paper Trading</h2>
57+
<p>Log hypothetical trades based on GEX signals and track theoretical P&L</p>
58+
<div class="app-status ready">
59+
<i class="fas fa-check-circle"></i> Ready
60+
</div>
61+
</div>
62+
</a>
5063
</div>
5164

5265
<footer class="landing-footer">

src/GexVisor.UI/Pages/Index.razor.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@
9494
color: white;
9595
}
9696

97+
.app-icon.trading {
98+
background: linear-gradient(135deg, var(--accent-green), #1b5e20);
99+
color: white;
100+
}
101+
97102
.app-info {
98103
flex: 1;
99104
}

0 commit comments

Comments
 (0)