Phase 5-UI: Generischer Core-Trade-Log + modulübergreifendes Dashboard
- Core: TradeRecord (Modell) + ITradeLogRepository (+ Mongo-Impl, Collection "trade_log"), in AddCorePersistence registriert. Realisiert den generischen, modulneutralen Trade-Log aus Entscheidung #2. - Dual-Write: PersistenceService schreibt geschlossene Copy-Trades zusaetzlich als generischen TradeRecord (ModuleName="CopyTrading"). - Neue DashboardView (UserControl + Designer): zeigt die letzten Trades ALLER Module (GetRecent) mit Konto-Aufloesung + Kurzauswertung (Gesamt-PnL, Anzahl, Aufschluesselung je Modul). btn_dashboard im Launcher, View "core.dashboard". - Build 0 Fehler. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8e2a92ad2e
commit
4f6c7fdb86
+17
@@ -176,6 +176,23 @@ internal static class Program
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
uiHost.RegisterView(new PolyTrader.Core.Modularity.ModuleView
|
||||||
|
{
|
||||||
|
Id = "core.dashboard",
|
||||||
|
Title = "Dashboard",
|
||||||
|
Group = "Core",
|
||||||
|
Order = 5,
|
||||||
|
PreferredWidth = 1200,
|
||||||
|
PreferredHeight = 650,
|
||||||
|
CreateControl = () =>
|
||||||
|
{
|
||||||
|
var view = new PolyTraderSharp.Ui.Views.DashboardView();
|
||||||
|
view.Initialize(
|
||||||
|
viewServices.GetRequiredService<PolyTrader.Core.Persistence.ITradeLogRepository>(),
|
||||||
|
viewServices.GetRequiredService<TradingState>());
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
});
|
||||||
// TODO Phase 5-UI: registrierte IPolyTraderModule durchlaufen und module.RegisterUi(uiHost) aufrufen.
|
// TODO Phase 5-UI: registrierte IPolyTraderModule durchlaufen und module.RegisterUi(uiHost) aufrufen.
|
||||||
|
|
||||||
var launcher = AppHost.Services.GetRequiredService<PolyTraderSharp.Ui.LauncherForm>();
|
var launcher = AppHost.Services.GetRequiredService<PolyTraderSharp.Ui.LauncherForm>();
|
||||||
|
|||||||
Generated
+10
@@ -200,6 +200,16 @@ namespace PolyTraderSharp.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap system_time {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("system_time", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
|
/// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -145,6 +145,9 @@
|
|||||||
<data name="coins_in_hand" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="coins_in_hand" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\coins_in_hand.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\coins_in_hand.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="error_log" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\error_log.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
<data name="add" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="add" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -169,7 +172,7 @@
|
|||||||
<data name="money_dollar" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="money_dollar" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\money_dollar.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\money_dollar.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="error_log" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="system_time" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\error_log.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\system_time.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Generated
+48
-37
@@ -25,6 +25,7 @@ namespace PolyTraderSharp.Ui
|
|||||||
btn_settings = new ToolStripButton();
|
btn_settings = new ToolStripButton();
|
||||||
btn_terminal = new ToolStripButton();
|
btn_terminal = new ToolStripButton();
|
||||||
btn_jobs = new ToolStripButton();
|
btn_jobs = new ToolStripButton();
|
||||||
|
btn_dashboard = new ToolStripButton();
|
||||||
toolstrip_quickbar = new ToolStrip();
|
toolstrip_quickbar = new ToolStrip();
|
||||||
btn_liveTrading = new ToolStripButton();
|
btn_liveTrading = new ToolStripButton();
|
||||||
btn_demoTrading = new ToolStripButton();
|
btn_demoTrading = new ToolStripButton();
|
||||||
@@ -37,9 +38,9 @@ namespace PolyTraderSharp.Ui
|
|||||||
toolstrip_quickbar.SuspendLayout();
|
toolstrip_quickbar.SuspendLayout();
|
||||||
statusStrip_info.SuspendLayout();
|
statusStrip_info.SuspendLayout();
|
||||||
SuspendLayout();
|
SuspendLayout();
|
||||||
//
|
//
|
||||||
// menuStrip
|
// menuStrip
|
||||||
//
|
//
|
||||||
menuStrip.ImageScalingSize = new Size(24, 24);
|
menuStrip.ImageScalingSize = new Size(24, 24);
|
||||||
menuStrip.Items.AddRange(new ToolStripItem[] { miDatei });
|
menuStrip.Items.AddRange(new ToolStripItem[] { miDatei });
|
||||||
menuStrip.Location = new Point(0, 0);
|
menuStrip.Location = new Point(0, 0);
|
||||||
@@ -47,39 +48,39 @@ namespace PolyTraderSharp.Ui
|
|||||||
menuStrip.Padding = new Padding(9, 3, 0, 3);
|
menuStrip.Padding = new Padding(9, 3, 0, 3);
|
||||||
menuStrip.Size = new Size(2599, 35);
|
menuStrip.Size = new Size(2599, 35);
|
||||||
menuStrip.TabIndex = 0;
|
menuStrip.TabIndex = 0;
|
||||||
//
|
//
|
||||||
// miDatei
|
// miDatei
|
||||||
//
|
//
|
||||||
miDatei.DropDownItems.AddRange(new ToolStripItem[] { miLegacy, miBeenden });
|
miDatei.DropDownItems.AddRange(new ToolStripItem[] { miLegacy, miBeenden });
|
||||||
miDatei.Name = "miDatei";
|
miDatei.Name = "miDatei";
|
||||||
miDatei.Size = new Size(69, 29);
|
miDatei.Size = new Size(69, 29);
|
||||||
miDatei.Text = "Datei";
|
miDatei.Text = "Datei";
|
||||||
//
|
//
|
||||||
// miLegacy
|
// miLegacy
|
||||||
//
|
//
|
||||||
miLegacy.Name = "miLegacy";
|
miLegacy.Name = "miLegacy";
|
||||||
miLegacy.Size = new Size(275, 34);
|
miLegacy.Size = new Size(275, 34);
|
||||||
miLegacy.Text = "Legacy-UI (alte Tabs)";
|
miLegacy.Text = "Legacy-UI (alte Tabs)";
|
||||||
//
|
//
|
||||||
// miBeenden
|
// miBeenden
|
||||||
//
|
//
|
||||||
miBeenden.Name = "miBeenden";
|
miBeenden.Name = "miBeenden";
|
||||||
miBeenden.Size = new Size(275, 34);
|
miBeenden.Size = new Size(275, 34);
|
||||||
miBeenden.Text = "Beenden";
|
miBeenden.Text = "Beenden";
|
||||||
//
|
//
|
||||||
// toolstrip_windows
|
// toolstrip_windows
|
||||||
//
|
//
|
||||||
toolstrip_windows.AutoSize = false;
|
toolstrip_windows.AutoSize = false;
|
||||||
toolstrip_windows.ImageScalingSize = new Size(64, 64);
|
toolstrip_windows.ImageScalingSize = new Size(64, 64);
|
||||||
toolstrip_windows.Items.AddRange(new ToolStripItem[] { btn_settings, btn_terminal, btn_jobs });
|
toolstrip_windows.Items.AddRange(new ToolStripItem[] { btn_settings, btn_terminal, btn_jobs, btn_dashboard });
|
||||||
toolstrip_windows.Location = new Point(0, 35);
|
toolstrip_windows.Location = new Point(0, 35);
|
||||||
toolstrip_windows.Name = "toolstrip_windows";
|
toolstrip_windows.Name = "toolstrip_windows";
|
||||||
toolstrip_windows.Size = new Size(2599, 70);
|
toolstrip_windows.Size = new Size(2599, 70);
|
||||||
toolstrip_windows.TabIndex = 3;
|
toolstrip_windows.TabIndex = 3;
|
||||||
toolstrip_windows.Text = "toolStrip1";
|
toolstrip_windows.Text = "toolStrip1";
|
||||||
//
|
//
|
||||||
// btn_settings
|
// btn_settings
|
||||||
//
|
//
|
||||||
btn_settings.BackColor = SystemColors.Control;
|
btn_settings.BackColor = SystemColors.Control;
|
||||||
btn_settings.Image = Properties.Resources.setting_tools;
|
btn_settings.Image = Properties.Resources.setting_tools;
|
||||||
btn_settings.ImageScaling = ToolStripItemImageScaling.None;
|
btn_settings.ImageScaling = ToolStripItemImageScaling.None;
|
||||||
@@ -88,49 +89,58 @@ namespace PolyTraderSharp.Ui
|
|||||||
btn_settings.Size = new Size(80, 65);
|
btn_settings.Size = new Size(80, 65);
|
||||||
btn_settings.Text = "Settings";
|
btn_settings.Text = "Settings";
|
||||||
btn_settings.TextImageRelation = TextImageRelation.ImageAboveText;
|
btn_settings.TextImageRelation = TextImageRelation.ImageAboveText;
|
||||||
//
|
//
|
||||||
// btn_terminal
|
// btn_terminal
|
||||||
//
|
//
|
||||||
btn_terminal.Image = Properties.Resources.error_log;
|
btn_terminal.Image = Properties.Resources.error_log;
|
||||||
btn_terminal.ImageScaling = ToolStripItemImageScaling.None;
|
btn_terminal.ImageScaling = ToolStripItemImageScaling.None;
|
||||||
btn_terminal.Name = "btn_terminal";
|
btn_terminal.Name = "btn_terminal";
|
||||||
btn_terminal.Size = new Size(136, 65);
|
btn_terminal.Size = new Size(136, 65);
|
||||||
btn_terminal.Text = "Terminal / Logs";
|
btn_terminal.Text = "Terminal / Logs";
|
||||||
btn_terminal.TextImageRelation = TextImageRelation.ImageAboveText;
|
btn_terminal.TextImageRelation = TextImageRelation.ImageAboveText;
|
||||||
//
|
//
|
||||||
// btn_jobs
|
// btn_jobs
|
||||||
//
|
//
|
||||||
btn_jobs.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
btn_jobs.Image = Properties.Resources.system_time;
|
||||||
|
btn_jobs.ImageScaling = ToolStripItemImageScaling.None;
|
||||||
btn_jobs.Name = "btn_jobs";
|
btn_jobs.Name = "btn_jobs";
|
||||||
btn_jobs.Size = new Size(100, 65);
|
btn_jobs.Size = new Size(106, 65);
|
||||||
btn_jobs.Text = "Server Jobs";
|
btn_jobs.Text = "Server Jobs";
|
||||||
|
btn_jobs.TextImageRelation = TextImageRelation.ImageAboveText;
|
||||||
//
|
//
|
||||||
|
// btn_dashboard
|
||||||
|
//
|
||||||
|
btn_dashboard.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||||
|
btn_dashboard.Name = "btn_dashboard";
|
||||||
|
btn_dashboard.Size = new Size(110, 65);
|
||||||
|
btn_dashboard.Text = "Dashboard";
|
||||||
|
//
|
||||||
// toolstrip_quickbar
|
// toolstrip_quickbar
|
||||||
//
|
//
|
||||||
toolstrip_quickbar.ImageScalingSize = new Size(24, 24);
|
toolstrip_quickbar.ImageScalingSize = new Size(24, 24);
|
||||||
toolstrip_quickbar.Items.AddRange(new ToolStripItem[] { btn_liveTrading, btn_demoTrading });
|
toolstrip_quickbar.Items.AddRange(new ToolStripItem[] { btn_liveTrading, btn_demoTrading });
|
||||||
toolstrip_quickbar.Location = new Point(0, 105);
|
toolstrip_quickbar.Location = new Point(0, 105);
|
||||||
toolstrip_quickbar.Name = "toolstrip_quickbar";
|
toolstrip_quickbar.Name = "toolstrip_quickbar";
|
||||||
toolstrip_quickbar.Size = new Size(2599, 28);
|
toolstrip_quickbar.Size = new Size(2599, 34);
|
||||||
toolstrip_quickbar.TabIndex = 4;
|
toolstrip_quickbar.TabIndex = 4;
|
||||||
toolstrip_quickbar.Text = "toolStrip2";
|
toolstrip_quickbar.Text = "toolStrip2";
|
||||||
//
|
//
|
||||||
// btn_liveTrading
|
// btn_liveTrading
|
||||||
//
|
//
|
||||||
btn_liveTrading.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
btn_liveTrading.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||||
btn_liveTrading.Name = "btn_liveTrading";
|
btn_liveTrading.Name = "btn_liveTrading";
|
||||||
btn_liveTrading.Size = new Size(200, 25);
|
btn_liveTrading.Size = new Size(137, 29);
|
||||||
btn_liveTrading.Text = "LiveTrading (—)";
|
btn_liveTrading.Text = "LiveTrading (—)";
|
||||||
//
|
//
|
||||||
// btn_demoTrading
|
// btn_demoTrading
|
||||||
//
|
//
|
||||||
btn_demoTrading.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
btn_demoTrading.DisplayStyle = ToolStripItemDisplayStyle.Text;
|
||||||
btn_demoTrading.Name = "btn_demoTrading";
|
btn_demoTrading.Name = "btn_demoTrading";
|
||||||
btn_demoTrading.Size = new Size(200, 25);
|
btn_demoTrading.Size = new Size(156, 29);
|
||||||
btn_demoTrading.Text = "DemoTrading (—)";
|
btn_demoTrading.Text = "DemoTrading (—)";
|
||||||
//
|
//
|
||||||
// statusStrip_info
|
// statusStrip_info
|
||||||
//
|
//
|
||||||
statusStrip_info.BackColor = Color.Gainsboro;
|
statusStrip_info.BackColor = Color.Gainsboro;
|
||||||
statusStrip_info.ImageScalingSize = new Size(24, 24);
|
statusStrip_info.ImageScalingSize = new Size(24, 24);
|
||||||
statusStrip_info.Items.AddRange(new ToolStripItem[] { lbl_trading, lbl_modules, lbl_ratelimit });
|
statusStrip_info.Items.AddRange(new ToolStripItem[] { lbl_trading, lbl_modules, lbl_ratelimit });
|
||||||
@@ -139,27 +149,27 @@ namespace PolyTraderSharp.Ui
|
|||||||
statusStrip_info.Size = new Size(2599, 32);
|
statusStrip_info.Size = new Size(2599, 32);
|
||||||
statusStrip_info.TabIndex = 5;
|
statusStrip_info.TabIndex = 5;
|
||||||
statusStrip_info.Text = "statusStrip1";
|
statusStrip_info.Text = "statusStrip1";
|
||||||
//
|
//
|
||||||
// lbl_trading
|
// lbl_trading
|
||||||
//
|
//
|
||||||
lbl_trading.Name = "lbl_trading";
|
lbl_trading.Name = "lbl_trading";
|
||||||
lbl_trading.Size = new Size(97, 25);
|
lbl_trading.Size = new Size(97, 25);
|
||||||
lbl_trading.Text = "Trading: —";
|
lbl_trading.Text = "Trading: —";
|
||||||
//
|
//
|
||||||
// lbl_modules
|
// lbl_modules
|
||||||
//
|
//
|
||||||
lbl_modules.Name = "lbl_modules";
|
lbl_modules.Name = "lbl_modules";
|
||||||
lbl_modules.Size = new Size(100, 25);
|
lbl_modules.Size = new Size(100, 25);
|
||||||
lbl_modules.Text = "Module: —";
|
lbl_modules.Text = "Module: —";
|
||||||
//
|
//
|
||||||
// lbl_ratelimit
|
// lbl_ratelimit
|
||||||
//
|
//
|
||||||
lbl_ratelimit.Name = "lbl_ratelimit";
|
lbl_ratelimit.Name = "lbl_ratelimit";
|
||||||
lbl_ratelimit.Size = new Size(66, 25);
|
lbl_ratelimit.Size = new Size(66, 25);
|
||||||
lbl_ratelimit.Text = "API: —";
|
lbl_ratelimit.Text = "API: —";
|
||||||
//
|
//
|
||||||
// LauncherForm
|
// LauncherForm
|
||||||
//
|
//
|
||||||
AutoScaleDimensions = new SizeF(10F, 25F);
|
AutoScaleDimensions = new SizeF(10F, 25F);
|
||||||
AutoScaleMode = AutoScaleMode.Font;
|
AutoScaleMode = AutoScaleMode.Font;
|
||||||
ClientSize = new Size(2599, 165);
|
ClientSize = new Size(2599, 165);
|
||||||
@@ -194,6 +204,7 @@ namespace PolyTraderSharp.Ui
|
|||||||
private ToolStripButton btn_settings;
|
private ToolStripButton btn_settings;
|
||||||
private ToolStripButton btn_terminal;
|
private ToolStripButton btn_terminal;
|
||||||
private ToolStripButton btn_jobs;
|
private ToolStripButton btn_jobs;
|
||||||
|
private ToolStripButton btn_dashboard;
|
||||||
private ToolStrip toolstrip_quickbar;
|
private ToolStrip toolstrip_quickbar;
|
||||||
private ToolStripButton btn_liveTrading;
|
private ToolStripButton btn_liveTrading;
|
||||||
private ToolStripButton btn_demoTrading;
|
private ToolStripButton btn_demoTrading;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace PolyTraderSharp.Ui
|
|||||||
btn_settings.Click += (_, _) => OpenView("core.settings");
|
btn_settings.Click += (_, _) => OpenView("core.settings");
|
||||||
btn_terminal.Click += (_, _) => OpenView("core.terminal");
|
btn_terminal.Click += (_, _) => OpenView("core.terminal");
|
||||||
btn_jobs.Click += (_, _) => OpenView("core.jobs");
|
btn_jobs.Click += (_, _) => OpenView("core.jobs");
|
||||||
|
btn_dashboard.Click += (_, _) => OpenView("core.dashboard");
|
||||||
btn_liveTrading.Click += (_, _) => CycleLiveTrading();
|
btn_liveTrading.Click += (_, _) => CycleLiveTrading();
|
||||||
btn_demoTrading.Click += (_, _) => CycleDemoTrading();
|
btn_demoTrading.Click += (_, _) => CycleDemoTrading();
|
||||||
miLegacy.Click += (_, _) => OpenLegacy();
|
miLegacy.Click += (_, _) => OpenLegacy();
|
||||||
|
|||||||
Generated
+202
@@ -0,0 +1,202 @@
|
|||||||
|
namespace PolyTraderSharp.Ui.Views
|
||||||
|
{
|
||||||
|
partial class DashboardView
|
||||||
|
{
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Vom Komponenten-Designer generierter Code
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.pnlTop = new System.Windows.Forms.Panel();
|
||||||
|
this.lblSummary = new System.Windows.Forms.Label();
|
||||||
|
this.btnRefresh = new System.Windows.Forms.Button();
|
||||||
|
this.dgvTrades = new System.Windows.Forms.DataGridView();
|
||||||
|
this.colModule = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colAccount = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colMarket = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colOutcome = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colSide = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colEntry = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colExit = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colSize = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colPnl = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colPnlPct = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.colClosedAt = new System.Windows.Forms.DataGridViewTextBoxColumn();
|
||||||
|
this.pnlTop.SuspendLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.dgvTrades)).BeginInit();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// pnlTop
|
||||||
|
//
|
||||||
|
this.pnlTop.Controls.Add(this.lblSummary);
|
||||||
|
this.pnlTop.Controls.Add(this.btnRefresh);
|
||||||
|
this.pnlTop.Dock = System.Windows.Forms.DockStyle.Top;
|
||||||
|
this.pnlTop.Location = new System.Drawing.Point(0, 0);
|
||||||
|
this.pnlTop.Name = "pnlTop";
|
||||||
|
this.pnlTop.Size = new System.Drawing.Size(1100, 40);
|
||||||
|
this.pnlTop.TabIndex = 0;
|
||||||
|
//
|
||||||
|
// lblSummary
|
||||||
|
//
|
||||||
|
this.lblSummary.AutoSize = true;
|
||||||
|
this.lblSummary.Location = new System.Drawing.Point(148, 12);
|
||||||
|
this.lblSummary.Name = "lblSummary";
|
||||||
|
this.lblSummary.Size = new System.Drawing.Size(63, 15);
|
||||||
|
this.lblSummary.TabIndex = 1;
|
||||||
|
this.lblSummary.Text = "—";
|
||||||
|
//
|
||||||
|
// btnRefresh
|
||||||
|
//
|
||||||
|
this.btnRefresh.Location = new System.Drawing.Point(8, 6);
|
||||||
|
this.btnRefresh.Name = "btnRefresh";
|
||||||
|
this.btnRefresh.Size = new System.Drawing.Size(130, 28);
|
||||||
|
this.btnRefresh.TabIndex = 0;
|
||||||
|
this.btnRefresh.Text = "Aktualisieren";
|
||||||
|
this.btnRefresh.UseVisualStyleBackColor = true;
|
||||||
|
//
|
||||||
|
// dgvTrades
|
||||||
|
//
|
||||||
|
this.dgvTrades.AllowUserToAddRows = false;
|
||||||
|
this.dgvTrades.AllowUserToDeleteRows = false;
|
||||||
|
this.dgvTrades.AutoGenerateColumns = false;
|
||||||
|
this.dgvTrades.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
|
||||||
|
this.dgvTrades.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
|
||||||
|
this.colModule,
|
||||||
|
this.colAccount,
|
||||||
|
this.colMarket,
|
||||||
|
this.colOutcome,
|
||||||
|
this.colSide,
|
||||||
|
this.colEntry,
|
||||||
|
this.colExit,
|
||||||
|
this.colSize,
|
||||||
|
this.colPnl,
|
||||||
|
this.colPnlPct,
|
||||||
|
this.colClosedAt});
|
||||||
|
this.dgvTrades.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||||
|
this.dgvTrades.Location = new System.Drawing.Point(0, 40);
|
||||||
|
this.dgvTrades.Name = "dgvTrades";
|
||||||
|
this.dgvTrades.ReadOnly = true;
|
||||||
|
this.dgvTrades.RowHeadersVisible = false;
|
||||||
|
this.dgvTrades.Size = new System.Drawing.Size(1100, 560);
|
||||||
|
this.dgvTrades.TabIndex = 1;
|
||||||
|
//
|
||||||
|
// colModule
|
||||||
|
//
|
||||||
|
this.colModule.DataPropertyName = "Module";
|
||||||
|
this.colModule.HeaderText = "Modul";
|
||||||
|
this.colModule.Name = "colModule";
|
||||||
|
this.colModule.Width = 110;
|
||||||
|
//
|
||||||
|
// colAccount
|
||||||
|
//
|
||||||
|
this.colAccount.DataPropertyName = "Account";
|
||||||
|
this.colAccount.HeaderText = "Konto";
|
||||||
|
this.colAccount.Name = "colAccount";
|
||||||
|
this.colAccount.Width = 130;
|
||||||
|
//
|
||||||
|
// colMarket
|
||||||
|
//
|
||||||
|
this.colMarket.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
|
||||||
|
this.colMarket.DataPropertyName = "Market";
|
||||||
|
this.colMarket.HeaderText = "Markt";
|
||||||
|
this.colMarket.Name = "colMarket";
|
||||||
|
//
|
||||||
|
// colOutcome
|
||||||
|
//
|
||||||
|
this.colOutcome.DataPropertyName = "Outcome";
|
||||||
|
this.colOutcome.HeaderText = "Outcome";
|
||||||
|
this.colOutcome.Name = "colOutcome";
|
||||||
|
this.colOutcome.Width = 80;
|
||||||
|
//
|
||||||
|
// colSide
|
||||||
|
//
|
||||||
|
this.colSide.DataPropertyName = "Side";
|
||||||
|
this.colSide.HeaderText = "Side";
|
||||||
|
this.colSide.Name = "colSide";
|
||||||
|
this.colSide.Width = 60;
|
||||||
|
//
|
||||||
|
// colEntry
|
||||||
|
//
|
||||||
|
this.colEntry.DataPropertyName = "EntryPrice";
|
||||||
|
this.colEntry.HeaderText = "Entry";
|
||||||
|
this.colEntry.Name = "colEntry";
|
||||||
|
this.colEntry.Width = 70;
|
||||||
|
//
|
||||||
|
// colExit
|
||||||
|
//
|
||||||
|
this.colExit.DataPropertyName = "ExitPrice";
|
||||||
|
this.colExit.HeaderText = "Exit";
|
||||||
|
this.colExit.Name = "colExit";
|
||||||
|
this.colExit.Width = 70;
|
||||||
|
//
|
||||||
|
// colSize
|
||||||
|
//
|
||||||
|
this.colSize.DataPropertyName = "Size";
|
||||||
|
this.colSize.HeaderText = "Size";
|
||||||
|
this.colSize.Name = "colSize";
|
||||||
|
this.colSize.Width = 70;
|
||||||
|
//
|
||||||
|
// colPnl
|
||||||
|
//
|
||||||
|
this.colPnl.DataPropertyName = "RealizedPnl";
|
||||||
|
this.colPnl.HeaderText = "PnL";
|
||||||
|
this.colPnl.Name = "colPnl";
|
||||||
|
this.colPnl.Width = 80;
|
||||||
|
//
|
||||||
|
// colPnlPct
|
||||||
|
//
|
||||||
|
this.colPnlPct.DataPropertyName = "PnlPercent";
|
||||||
|
this.colPnlPct.HeaderText = "PnL %";
|
||||||
|
this.colPnlPct.Name = "colPnlPct";
|
||||||
|
this.colPnlPct.Width = 70;
|
||||||
|
//
|
||||||
|
// colClosedAt
|
||||||
|
//
|
||||||
|
this.colClosedAt.DataPropertyName = "ClosedAt";
|
||||||
|
this.colClosedAt.HeaderText = "Geschlossen";
|
||||||
|
this.colClosedAt.Name = "colClosedAt";
|
||||||
|
this.colClosedAt.Width = 140;
|
||||||
|
//
|
||||||
|
// DashboardView
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.Controls.Add(this.dgvTrades);
|
||||||
|
this.Controls.Add(this.pnlTop);
|
||||||
|
this.Name = "DashboardView";
|
||||||
|
this.Size = new System.Drawing.Size(1100, 600);
|
||||||
|
this.pnlTop.ResumeLayout(false);
|
||||||
|
this.pnlTop.PerformLayout();
|
||||||
|
((System.ComponentModel.ISupportInitialize)(this.dgvTrades)).EndInit();
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private System.Windows.Forms.Panel pnlTop;
|
||||||
|
private System.Windows.Forms.Button btnRefresh;
|
||||||
|
private System.Windows.Forms.Label lblSummary;
|
||||||
|
private System.Windows.Forms.DataGridView dgvTrades;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colModule;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colAccount;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colMarket;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colOutcome;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colSide;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colEntry;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colExit;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colSize;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colPnl;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colPnlPct;
|
||||||
|
private System.Windows.Forms.DataGridViewTextBoxColumn colClosedAt;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using PolyTrader.Core.Persistence;
|
||||||
|
|
||||||
|
namespace PolyTraderSharp.Ui.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Modulübergreifendes Dashboard: zeigt die letzten Trades ALLER Module aus dem
|
||||||
|
/// generischen Core-Trade-Log (ITradeLogRepository) und eine Kurzauswertung.
|
||||||
|
/// Designbar (DashboardView.Designer.cs).
|
||||||
|
/// </summary>
|
||||||
|
public partial class DashboardView : UserControl
|
||||||
|
{
|
||||||
|
private ITradeLogRepository? _tradeLog;
|
||||||
|
private TradingState? _state;
|
||||||
|
|
||||||
|
public DashboardView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
colEntry.DefaultCellStyle.Format = "F3";
|
||||||
|
colExit.DefaultCellStyle.Format = "F3";
|
||||||
|
colSize.DefaultCellStyle.Format = "F2";
|
||||||
|
colPnl.DefaultCellStyle.Format = "F2";
|
||||||
|
colPnlPct.DefaultCellStyle.Format = "F1";
|
||||||
|
colClosedAt.DefaultCellStyle.Format = "dd.MM.yyyy HH:mm";
|
||||||
|
btnRefresh.Click += (_, _) => LoadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize(ITradeLogRepository tradeLog, TradingState state)
|
||||||
|
{
|
||||||
|
_tradeLog = tradeLog;
|
||||||
|
_state = state;
|
||||||
|
LoadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadData()
|
||||||
|
{
|
||||||
|
if (_tradeLog == null) return;
|
||||||
|
|
||||||
|
var rows = _tradeLog.GetRecent(300).Select(r => new DashboardTradeRow
|
||||||
|
{
|
||||||
|
Module = r.ModuleName,
|
||||||
|
Account = ResolveAccount(r.AccountId, r.IsDemo),
|
||||||
|
Market = r.MarketQuestion,
|
||||||
|
Outcome = r.Outcome,
|
||||||
|
Side = r.Side,
|
||||||
|
EntryPrice = r.EntryPrice,
|
||||||
|
ExitPrice = r.ExitPrice,
|
||||||
|
Size = r.Size,
|
||||||
|
RealizedPnl = r.RealizedPnl,
|
||||||
|
PnlPercent = r.PnlPercent,
|
||||||
|
ClosedAt = r.ClosedAt
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
dgvTrades.DataSource = new BindingList<DashboardTradeRow>(rows);
|
||||||
|
|
||||||
|
decimal totalPnl = rows.Sum(x => x.RealizedPnl);
|
||||||
|
var perModule = rows.GroupBy(x => x.Module).Select(g => $"{g.Key}: {g.Count()}");
|
||||||
|
lblSummary.Text = $"{rows.Count} Trades | PnL gesamt: {totalPnl:F2} USDC | {string.Join(" · ", perModule)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ResolveAccount(int accountId, bool isDemo)
|
||||||
|
{
|
||||||
|
string suffix = isDemo ? " (Demo)" : "";
|
||||||
|
if (_state != null && _state.Accounts.TryGetValue(accountId, out var acc) && !string.IsNullOrEmpty(acc.Name))
|
||||||
|
return acc.Name + suffix;
|
||||||
|
return $"#{accountId}{suffix}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Anzeige-Zeile für das Dashboard-Grid (Account bereits zu Name aufgelöst).</summary>
|
||||||
|
public class DashboardTradeRow
|
||||||
|
{
|
||||||
|
public string Module { get; set; } = string.Empty;
|
||||||
|
public string Account { get; set; } = string.Empty;
|
||||||
|
public string Market { get; set; } = string.Empty;
|
||||||
|
public string Outcome { get; set; } = string.Empty;
|
||||||
|
public string Side { get; set; } = string.Empty;
|
||||||
|
public decimal EntryPrice { get; set; }
|
||||||
|
public decimal ExitPrice { get; set; }
|
||||||
|
public decimal Size { get; set; }
|
||||||
|
public decimal RealizedPnl { get; set; }
|
||||||
|
public decimal PnlPercent { get; set; }
|
||||||
|
public DateTime ClosedAt { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PolyTrader.Core.Persistence;
|
||||||
using PolyTrader.Modules.CopyTrading.Persistence;
|
using PolyTrader.Modules.CopyTrading.Persistence;
|
||||||
using PolyTraderSharp.Models;
|
using PolyTraderSharp.Models;
|
||||||
|
|
||||||
@@ -10,13 +11,15 @@ namespace PolyTraderSharp.Services
|
|||||||
{
|
{
|
||||||
private readonly ChannelReader<ClosedTrade> _tradeReader;
|
private readonly ChannelReader<ClosedTrade> _tradeReader;
|
||||||
private readonly ICopyTradeLogRepository _tradeLog;
|
private readonly ICopyTradeLogRepository _tradeLog;
|
||||||
|
private readonly ITradeLogRepository _coreTradeLog;
|
||||||
private readonly TerminalLogger _logger;
|
private readonly TerminalLogger _logger;
|
||||||
private readonly JobStatusRow _jobStatus;
|
private readonly JobStatusRow _jobStatus;
|
||||||
|
|
||||||
public PersistenceService(ChannelReader<ClosedTrade> tradeReader, ICopyTradeLogRepository tradeLog, TerminalLogger logger, JobManager jobManager)
|
public PersistenceService(ChannelReader<ClosedTrade> tradeReader, ICopyTradeLogRepository tradeLog, ITradeLogRepository coreTradeLog, TerminalLogger logger, JobManager jobManager)
|
||||||
{
|
{
|
||||||
_tradeReader = tradeReader;
|
_tradeReader = tradeReader;
|
||||||
_tradeLog = tradeLog;
|
_tradeLog = tradeLog;
|
||||||
|
_coreTradeLog = coreTradeLog;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
|
||||||
_jobStatus = new JobStatusRow
|
_jobStatus = new JobStatusRow
|
||||||
@@ -43,6 +46,7 @@ namespace PolyTraderSharp.Services
|
|||||||
|
|
||||||
// One-time index setup (moved out of hot loop)
|
// One-time index setup (moved out of hot loop)
|
||||||
_tradeLog.EnsureIndexes();
|
_tradeLog.EnsureIndexes();
|
||||||
|
_coreTradeLog.EnsureIndexes();
|
||||||
|
|
||||||
// We do a loop waiting for items in the channel
|
// We do a loop waiting for items in the channel
|
||||||
await foreach(var trade in _tradeReader.ReadAllAsync(stoppingToken))
|
await foreach(var trade in _tradeReader.ReadAllAsync(stoppingToken))
|
||||||
@@ -72,7 +76,27 @@ namespace PolyTraderSharp.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
_tradeLog.Insert(trade);
|
_tradeLog.Insert(trade);
|
||||||
|
|
||||||
|
// Dual-Write: generischer, modulübergreifender Core-Trade-Log (fürs Dashboard).
|
||||||
|
_coreTradeLog.Insert(new TradeRecord
|
||||||
|
{
|
||||||
|
ModuleName = "CopyTrading",
|
||||||
|
AccountId = trade.AccountId,
|
||||||
|
IsDemo = trade.IsDemo,
|
||||||
|
TokenId = trade.TokenId,
|
||||||
|
MarketQuestion = trade.MarketQuestion,
|
||||||
|
Outcome = trade.Outcome,
|
||||||
|
Side = trade.Side,
|
||||||
|
EntryPrice = trade.EntryPrice,
|
||||||
|
ExitPrice = trade.ExitPrice,
|
||||||
|
Size = trade.Size,
|
||||||
|
RealizedPnl = trade.RealizedPnl,
|
||||||
|
PnlPercent = trade.PnlPercent,
|
||||||
|
OpenedAt = trade.OpenedAt,
|
||||||
|
ClosedAt = trade.ClosedAt,
|
||||||
|
ExitReason = trade.ExitReason
|
||||||
|
});
|
||||||
|
|
||||||
_logger.Debug($"Saved ClosedTrade {trade.TradeId} to MongoDB");
|
_logger.Debug($"Saved ClosedTrade {trade.TradeId} to MongoDB");
|
||||||
_jobStatus.LastRun = DateTime.Now;
|
_jobStatus.LastRun = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace PolyTrader.Core.DependencyInjection
|
|||||||
services.AddSingleton<IAccountRepository, MongoAccountRepository>();
|
services.AddSingleton<IAccountRepository, MongoAccountRepository>();
|
||||||
services.AddSingleton<IMarketRepository, MongoMarketRepository>();
|
services.AddSingleton<IMarketRepository, MongoMarketRepository>();
|
||||||
services.AddSingleton<IPositionRepository, MongoPositionRepository>();
|
services.AddSingleton<IPositionRepository, MongoPositionRepository>();
|
||||||
|
services.AddSingleton<ITradeLogRepository, MongoTradeLogRepository>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PolyTraderSharp.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generischer, modulübergreifender Trade-Log-Eintrag (Collection "trade_log").
|
||||||
|
/// Jedes Modul, das Trades abschließt, schreibt hier einen neutralen Eintrag —
|
||||||
|
/// so kann das Core-Dashboard die Trades ALLER Module gemeinsam auswerten.
|
||||||
|
/// Modulspezifische Details (z.B. Copytrading-SourceTrader) bleiben im jeweiligen
|
||||||
|
/// Modul-Log (z.B. ClosedTrade).
|
||||||
|
/// </summary>
|
||||||
|
public class TradeRecord
|
||||||
|
{
|
||||||
|
[MongoDB.Bson.Serialization.Attributes.BsonId]
|
||||||
|
public string Id { get; set; } = MongoDB.Bson.ObjectId.GenerateNewId().ToString();
|
||||||
|
|
||||||
|
/// <summary>Herkunftsmodul, z.B. "CopyTrading".</summary>
|
||||||
|
public string ModuleName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public int AccountId { get; set; }
|
||||||
|
public bool IsDemo { get; set; }
|
||||||
|
|
||||||
|
public string TokenId { get; set; } = string.Empty;
|
||||||
|
public string MarketQuestion { get; set; } = string.Empty;
|
||||||
|
public string Outcome { get; set; } = string.Empty;
|
||||||
|
public string Side { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public decimal EntryPrice { get; set; }
|
||||||
|
public decimal ExitPrice { get; set; }
|
||||||
|
public decimal Size { get; set; }
|
||||||
|
|
||||||
|
public decimal RealizedPnl { get; set; }
|
||||||
|
public decimal PnlPercent { get; set; }
|
||||||
|
|
||||||
|
public DateTime OpenedAt { get; set; }
|
||||||
|
public DateTime ClosedAt { get; set; }
|
||||||
|
public string ExitReason { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using PolyTraderSharp.Models;
|
||||||
|
|
||||||
|
namespace PolyTrader.Core.Persistence
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generischer, modulübergreifender Trade-Log (Collection "trade_log").
|
||||||
|
/// Speist das Core-Dashboard mit den Trades aller Module.
|
||||||
|
/// </summary>
|
||||||
|
public interface ITradeLogRepository
|
||||||
|
{
|
||||||
|
void EnsureIndexes();
|
||||||
|
void Insert(TradeRecord record);
|
||||||
|
|
||||||
|
/// <summary>Die neuesten Einträge über alle Module (nach ClosedAt absteigend).</summary>
|
||||||
|
List<TradeRecord> GetRecent(int limit);
|
||||||
|
|
||||||
|
List<TradeRecord> Find(Expression<Func<TradeRecord, bool>> predicate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using PolyTraderSharp.Models;
|
||||||
|
|
||||||
|
namespace PolyTrader.Core.Persistence.Mongo
|
||||||
|
{
|
||||||
|
public class MongoTradeLogRepository : ITradeLogRepository
|
||||||
|
{
|
||||||
|
private readonly IMongoCollection<TradeRecord> _col;
|
||||||
|
|
||||||
|
public MongoTradeLogRepository(IMongoDatabase db)
|
||||||
|
{
|
||||||
|
_col = db.GetCollection<TradeRecord>("trade_log");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnsureIndexes()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_col.Indexes.CreateOne(new CreateIndexModel<TradeRecord>(
|
||||||
|
Builders<TradeRecord>.IndexKeys.Descending(x => x.ClosedAt)));
|
||||||
|
_col.Indexes.CreateOne(new CreateIndexModel<TradeRecord>(
|
||||||
|
Builders<TradeRecord>.IndexKeys.Ascending(x => x.ModuleName)));
|
||||||
|
_col.Indexes.CreateOne(new CreateIndexModel<TradeRecord>(
|
||||||
|
Builders<TradeRecord>.IndexKeys.Ascending(x => x.AccountId)));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Insert(TradeRecord record) => _col.InsertOne(record);
|
||||||
|
|
||||||
|
public List<TradeRecord> GetRecent(int limit) =>
|
||||||
|
_col.Find(_ => true).SortByDescending(x => x.ClosedAt).Limit(limit).ToList();
|
||||||
|
|
||||||
|
public List<TradeRecord> Find(Expression<Func<TradeRecord, bool>> predicate) =>
|
||||||
|
_col.Find(predicate).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user