@backtest-kit/ui 5.0.0 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,25 +67,127 @@ setLogger({
67
67
 
68
68
  ## 📐 Dashboard Revenue Math
69
69
 
70
- The **Revenue** metrics on the dashboard are calculated in **dollar terms**, assuming a fixed position size of **$100 per DCA entry**.
70
+ The **Revenue** metrics on the dashboard are calculated in **dollar terms** by summing the `pnlCost` field from all closed signals within each time window.
71
71
 
72
72
  ### Dollar PnL formula
73
73
 
74
74
  ```
75
- dollar_pnl = pnlPercentage × totalEntries
75
+ revenue[window] = Σ signal.pnl.pnlCost (for all closed signals in that window)
76
76
  ```
77
77
 
78
- | `totalEntries` | Effective position | Dollar PnL (example: +5%) |
79
- |:--------------:|-------------------:|-------------------------:|
80
- | 1 | $100 | +$5.00 |
81
- | 2 | $200 | +$10.00 |
82
- | 3 | $300 | +$15.00 |
78
+ `pnlCost` is computed by the backend (`toProfitLossDto`) as:
83
79
 
84
- - **`pnlPercentage`** — percentage PnL as stored in the signal (e.g. `5` = 5 %). It does **not** change with DCA averaging.
85
- - **`totalEntries`** — number of DCA buy entries that were executed for the signal (`IPublicSignalRow.totalEntries`). A regular (non-DCA) signal has `totalEntries = 1`, so the formula degrades to the plain percentage.
86
- - **Fallback** — if `totalEntries` is `0` or absent (legacy data), the raw `pnlPercentage` is used as-is.
80
+ ```
81
+ pnlCost = (pnlPercentage / 100) × pnlEntries
82
+ ```
83
+
84
+ | Field | Source | Description |
85
+ |-------|--------|-------------|
86
+ | `pnl.pnlCost` | `IStorageSignalRow` | Absolute P&L in USD — the only value summed for revenue |
87
+ | `pnl.pnlPercentage` | `IStorageSignalRow` | Percentage P&L (accounts for DCA-weighted entry price, slippage, and fees) |
88
+ | `pnl.pnlEntries` | `IStorageSignalRow` | Total invested capital in USD — sum of all entry costs (`Σ entry.cost`) |
89
+
90
+ **Example** (1 DCA entry at $100, position closed +5%):
91
+
92
+ | DCA entries | `pnlEntries` | `pnlPercentage` | `pnlCost` |
93
+ |:-----------:|-------------:|----------------:|----------:|
94
+ | 1 | $100 | 5 % | +$5.00 |
95
+ | 2 | $200 | 5 % | +$10.00 |
96
+ | 3 | $300 | 5 % | +$15.00 |
97
+
98
+ ### Time windows
99
+
100
+ The anchor point depends on execution mode:
101
+
102
+ - **Backtest mode** — latest `updatedAt` across all closed signals (time windows are relative to the end of the run)
103
+ - **Live mode** — `Date.now()` (wall-clock time)
104
+
105
+ | Window | Range |
106
+ |--------|-------|
107
+ | Today | `>= startOf(anchorDay)` |
108
+ | Yesterday | `[anchorDay − 1d, anchorDay)` |
109
+ | 7 days | `>= anchorDay − 7d` |
110
+ | 31 days | `>= anchorDay − 31d` |
111
+
112
+ Revenue and signal count are tracked separately for each window and aggregated across all symbols on the Dashboard.
113
+
114
+ ## 📐 Position PNL Math
115
+
116
+ ### Effective entry price (DCA-weighted)
117
+
118
+ When multiple DCA entries exist, the effective open price is a **cost-weighted harmonic mean**:
119
+
120
+ ```
121
+ effectivePrice = Σcost / Σ(cost / price)
122
+ ```
123
+
124
+ This is the correct formula for fixed-dollar entries (not simple average), because buying $100 worth at different prices gives different coin quantities.
125
+
126
+ ### Partial closes (PP/PL)
127
+
128
+ Each partial stores a `costBasisAtClose` snapshot — the running dollar cost-basis **before** that partial fired. This avoids replaying the full entry history on every call.
129
+
130
+ **Cost-basis replay:**
131
+
132
+ ```
133
+ for each partial[i]:
134
+ closedDollar += (percent[i] / 100) × costBasisAtClose[i]
135
+ remainingCostBasis = costBasisAtClose[i] × (1 - percent[i] / 100)
136
+
137
+ # DCA entries added AFTER the last partial are appended:
138
+ remainingCostBasis += Σ entry.cost for entries[lastEntryCount..]
139
+
140
+ totalClosedPercent = closedDollar / totalInvested × 100
141
+ ```
142
+
143
+ **Effective price through partials** is computed iteratively so that a partial sell does not change the entry price of the remaining coins:
144
+
145
+ ```
146
+ # partial[0]:
147
+ effPrice = costBasisAtClose[0] / Σ(cost/price for entries[0..cnt[0]])
148
+
149
+ # partial[j]:
150
+ remainingCB = prev.costBasisAtClose × (1 - prev.percent / 100)
151
+ oldCoins = remainingCB / effPrice ← coins still held
152
+ newCoins = Σ(cost/price for DCA entries between j-1 and j)
153
+ effPrice = (remainingCB + newCost) / (oldCoins + newCoins)
154
+ ```
155
+
156
+ ### toProfitLossDto — weighted PNL with slippage & fees
157
+
158
+ **Without partials:**
159
+
160
+ ```
161
+ priceOpenSlip = effectivePrice × (1 ± slippage)
162
+ priceCloseSlip = priceClose × (1 ∓ slippage)
163
+
164
+ pnlPercentage = (priceCloseSlip - priceOpenSlip) / priceOpenSlip × 100
165
+ fee = CC_PERCENT_FEE × (1 + priceCloseSlip / priceOpenSlip)
166
+ pnlPercentage -= fee
167
+ ```
168
+
169
+ **With partials — dollar-weighted sum:**
170
+
171
+ ```
172
+ weight[i] = (percent[i] / 100 × costBasisAtClose[i]) / totalInvested
173
+
174
+ totalWeightedPnl = Σ weight[i] × pnl[i] # each partial at its own effectivePrice
175
+ + remainingWeight × pnlRemaining # rest closed at final priceClose
176
+
177
+ fee = CC_PERCENT_FEE # open (once)
178
+ + Σ CC_PERCENT_FEE × weight[i] × (closeSlip[i] / openSlip[i]) # per partial
179
+ + CC_PERCENT_FEE × remainingWeight × (closeSlip / openSlip) # final close
180
+
181
+ pnlPercentage = totalWeightedPnl - fee
182
+ pnlCost = pnlPercentage / 100 × totalInvested
183
+ ```
87
184
 
88
- This scaling is applied to all time-window revenue fields: *today*, *yesterday*, *7 days*, and *31 days*.
185
+ | Field | Description |
186
+ |-------|-------------|
187
+ | `totalInvested` | `Σ entry.cost` (or `CC_POSITION_ENTRY_COST` if no `_entry`) |
188
+ | `weight[i]` | Real dollar share of each partial relative to `totalInvested` |
189
+ | `effectivePrice` at partial `i` | Computed via iterative `costBasisAtClose` replay up to `partials[i]` |
190
+ | `priceOpen` in result | `getEffectivePriceOpen(signal)` — DCA-weighted harmonic mean across all entries |
89
191
 
90
192
  ## 🖥️ Dashboard Views
91
193
 
package/build/index.cjs CHANGED
@@ -906,22 +906,6 @@ class SymbolMetaService {
906
906
  }
907
907
  }
908
908
 
909
- const PRICE_TIMEOUT = 120000;
910
- const CREATE_KEY_FN = (symbol, strategyName, exchangeName, frameName, backtest) => {
911
- const parts = [symbol, strategyName, exchangeName];
912
- if (frameName)
913
- parts.push(frameName);
914
- parts.push(backtest ? "backtest" : "live");
915
- return parts.join(":");
916
- };
917
- const GET_SUBJECT_FN = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
918
- const GET_PRICE_FN = async (symbol, strategyName, exchangeName, frameName, backtest) => {
919
- const priceSubject = GET_SUBJECT_FN(symbol, strategyName, exchangeName, frameName, backtest);
920
- if (priceSubject.data) {
921
- return priceSubject.data;
922
- }
923
- return await functoolsKit.waitForNext(priceSubject, (data) => !!data, PRICE_TIMEOUT);
924
- };
925
909
  class PriceConnectionService {
926
910
  constructor() {
927
911
  this.loggerService = inject(TYPES.loggerService);
@@ -933,19 +917,8 @@ class PriceConnectionService {
933
917
  frameName,
934
918
  backtest,
935
919
  });
936
- const currentPrice = await GET_PRICE_FN(symbol, strategyName, exchangeName, frameName, backtest);
937
- if (typeof currentPrice === "symbol") {
938
- throw new Error(`Price for ${CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest)} not received within timeout`);
939
- }
940
- return currentPrice;
920
+ return await backtestKit.lib.priceMetaService.getCurrentPrice(symbol, { strategyName, exchangeName, frameName }, backtest);
941
921
  };
942
- this.init = functoolsKit.singleshot(async () => {
943
- this.loggerService.log("priceConnectionService init");
944
- backtestKit.listenSignal((event) => {
945
- const priceSubject = GET_SUBJECT_FN(event.symbol, event.strategyName, event.exchangeName, event.frameName, event.backtest);
946
- event.currentPrice && priceSubject.next(event.currentPrice);
947
- });
948
- });
949
922
  }
950
923
  }
951
924
 
package/build/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  import http from 'http';
2
- import { isObject, singleshot, pickDocuments, str, memoize, BehaviorSubject, waitForNext, errorData, getErrorMessage } from 'functools-kit';
2
+ import { isObject, singleshot, pickDocuments, str, memoize, errorData, getErrorMessage } from 'functools-kit';
3
3
  import micro from 'micro';
4
4
  import Router from 'router';
5
5
  import finalhandler from 'finalhandler';
6
6
  import serveHandler from 'serve-handler';
7
7
  import os from 'os';
8
8
  import { createActivator } from 'di-kit';
9
- import { Exchange, Notification, Storage, Log, Live, listenSignal } from 'backtest-kit';
9
+ import { Exchange, Notification, Storage, Log, Live, lib } from 'backtest-kit';
10
10
  import fs, { readdir, readFile } from 'fs/promises';
11
11
  import path, { join, dirname } from 'path';
12
12
  import { createRequire } from 'module';
@@ -903,22 +903,6 @@ class SymbolMetaService {
903
903
  }
904
904
  }
905
905
 
906
- const PRICE_TIMEOUT = 120000;
907
- const CREATE_KEY_FN = (symbol, strategyName, exchangeName, frameName, backtest) => {
908
- const parts = [symbol, strategyName, exchangeName];
909
- if (frameName)
910
- parts.push(frameName);
911
- parts.push(backtest ? "backtest" : "live");
912
- return parts.join(":");
913
- };
914
- const GET_SUBJECT_FN = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
915
- const GET_PRICE_FN = async (symbol, strategyName, exchangeName, frameName, backtest) => {
916
- const priceSubject = GET_SUBJECT_FN(symbol, strategyName, exchangeName, frameName, backtest);
917
- if (priceSubject.data) {
918
- return priceSubject.data;
919
- }
920
- return await waitForNext(priceSubject, (data) => !!data, PRICE_TIMEOUT);
921
- };
922
906
  class PriceConnectionService {
923
907
  constructor() {
924
908
  this.loggerService = inject(TYPES.loggerService);
@@ -930,19 +914,8 @@ class PriceConnectionService {
930
914
  frameName,
931
915
  backtest,
932
916
  });
933
- const currentPrice = await GET_PRICE_FN(symbol, strategyName, exchangeName, frameName, backtest);
934
- if (typeof currentPrice === "symbol") {
935
- throw new Error(`Price for ${CREATE_KEY_FN(symbol, strategyName, exchangeName, frameName, backtest)} not received within timeout`);
936
- }
937
- return currentPrice;
917
+ return await lib.priceMetaService.getCurrentPrice(symbol, { strategyName, exchangeName, frameName }, backtest);
938
918
  };
939
- this.init = singleshot(async () => {
940
- this.loggerService.log("priceConnectionService init");
941
- listenSignal((event) => {
942
- const priceSubject = GET_SUBJECT_FN(event.symbol, event.strategyName, event.exchangeName, event.frameName, event.backtest);
943
- event.currentPrice && priceSubject.next(event.currentPrice);
944
- });
945
- });
946
919
  }
947
920
  }
948
921
 
@@ -1 +1 @@
1
- import{f as n,az as o}from"./index-3gnGrSPi.js";const d=()=>n(o,{children:"\n body {\n background-color: #ddd !important;\n }\n "});export{d as B};
1
+ import{f as n,az as o}from"./index-CBPue3Jb.js";const d=()=>n(o,{children:"\n body {\n background-color: #ddd !important;\n }\n "});export{d as B};
@@ -1 +1 @@
1
- import{f as e,i as t,B as r,J as s}from"./index-3gnGrSPi.js";const a=({className:a,symbol:i,style:o,sx:n})=>e(s,{children:async()=>{try{const s=(await t.symbolGlobalService.getSymbolMap())[i],l=null==s?void 0:s.icon,c=(null==s?void 0:s.color)||"#ccc";return e(r,{className:a,sx:{position:"relative",width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",background:l?"transparent":c,...n},style:o,children:l?e("img",{loading:"lazy",crossOrigin:"anonymous",src:l,alt:i,style:{width:"100%",height:"100%",borderRadius:"50%",objectFit:"contain"},onError:e=>{const t=e.target,r=t.parentElement;r&&(r.style.background=c,t.style.display="none")}}):e(r,{sx:{width:"60%",height:"60%",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.2)"}})})}catch(s){return e(r,{className:a,sx:{position:"relative",width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",background:"#ccc",...n},style:o,children:e(r,{sx:{width:"60%",height:"60%",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.2)"}})})}}});export{a as I};
1
+ import{f as e,i as t,B as r,J as s}from"./index-CBPue3Jb.js";const a=({className:a,symbol:i,style:o,sx:n})=>e(s,{children:async()=>{try{const s=(await t.symbolGlobalService.getSymbolMap())[i],l=null==s?void 0:s.icon,c=(null==s?void 0:s.color)||"#ccc";return e(r,{className:a,sx:{position:"relative",width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",background:l?"transparent":c,...n},style:o,children:l?e("img",{loading:"lazy",crossOrigin:"anonymous",src:l,alt:i,style:{width:"100%",height:"100%",borderRadius:"50%",objectFit:"contain"},onError:e=>{const t=e.target,r=t.parentElement;r&&(r.style.background=c,t.style.display="none")}}):e(r,{sx:{width:"60%",height:"60%",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.2)"}})})}catch(s){return e(r,{className:a,sx:{position:"relative",width:24,height:24,borderRadius:"50%",display:"flex",alignItems:"center",justifyContent:"center",background:"#ccc",...n},style:o,children:e(r,{sx:{width:"60%",height:"60%",borderRadius:"50%",backgroundColor:"rgba(255, 255, 255, 0.2)"}})})}}});export{a as I};
@@ -1 +1 @@
1
- import{c as o,f as r}from"./index-3gnGrSPi.js";const a=o(r("path",{d:"M15.41 16.59 10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"}),"KeyboardArrowLeft");export{a as K};
1
+ import{c as o,f as r}from"./index-CBPue3Jb.js";const a=o(r("path",{d:"M15.41 16.59 10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"}),"KeyboardArrowLeft");export{a as K};
@@ -1 +1 @@
1
- import{aA as e,aB as t,r as a,aC as s,f as i,aD as n,aE as o,aF as r,aG as d,aH as m,aI as u,aJ as p,aK as x,c}from"./index-3gnGrSPi.js";const h=e(),l=["className","component","disableGutters","fixed","maxWidth","classes"],b=m(),f=h("div",{name:"MuiContainer",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:a}=e;return[t.root,t[`maxWidth${o(String(a.maxWidth))}`],a.fixed&&t.fixed,a.disableGutters&&t.disableGutters]}}),g=e=>r({props:e,name:"MuiContainer",defaultTheme:b});const W=function(e={}){const{createStyledComponent:r=f,useThemeProps:m=g,componentName:p="MuiContainer"}=e,x=r(({theme:e,ownerState:a})=>t({width:"100%",marginLeft:"auto",boxSizing:"border-box",marginRight:"auto",display:"block"},!a.disableGutters&&{paddingLeft:e.spacing(2),paddingRight:e.spacing(2),[e.breakpoints.up("sm")]:{paddingLeft:e.spacing(3),paddingRight:e.spacing(3)}}),({theme:e,ownerState:t})=>t.fixed&&Object.keys(e.breakpoints.values).reduce((t,a)=>{const s=a,i=e.breakpoints.values[s];return 0!==i&&(t[e.breakpoints.up(s)]={maxWidth:`${i}${e.breakpoints.unit}`}),t},{}),({theme:e,ownerState:a})=>t({},"xs"===a.maxWidth&&{[e.breakpoints.up("xs")]:{maxWidth:Math.max(e.breakpoints.values.xs,444)}},a.maxWidth&&"xs"!==a.maxWidth&&{[e.breakpoints.up(a.maxWidth)]:{maxWidth:`${e.breakpoints.values[a.maxWidth]}${e.breakpoints.unit}`}}));return a.forwardRef(function(e,a){const r=m(e),{className:c,component:h="div",disableGutters:b=!1,fixed:f=!1,maxWidth:g="lg"}=r,W=s(r,l),k=t({},r,{component:h,disableGutters:b,fixed:f,maxWidth:g}),S=((e,t)=>{const{classes:a,fixed:s,disableGutters:i,maxWidth:n}=e,r={root:["root",n&&`maxWidth${o(String(n))}`,s&&"fixed",i&&"disableGutters"]};return d(r,e=>u(t,e),a)})(k,p);return i(x,t({as:h,ownerState:k,className:n(S.root,c),ref:a},W))})}({createStyledComponent:x("div",{name:"MuiContainer",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:a}=e;return[t.root,t[`maxWidth${o(String(a.maxWidth))}`],a.fixed&&t.fixed,a.disableGutters&&t.disableGutters]}}),useThemeProps:e=>p({props:e,name:"MuiContainer"})}),k=c(i("path",{d:"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"}),"Refresh");export{W as C,k as R};
1
+ import{aA as e,aB as t,r as a,aC as s,f as i,aD as n,aE as o,aF as r,aG as d,aH as m,aI as u,aJ as p,aK as x,c}from"./index-CBPue3Jb.js";const h=e(),l=["className","component","disableGutters","fixed","maxWidth","classes"],b=m(),f=h("div",{name:"MuiContainer",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:a}=e;return[t.root,t[`maxWidth${o(String(a.maxWidth))}`],a.fixed&&t.fixed,a.disableGutters&&t.disableGutters]}}),g=e=>r({props:e,name:"MuiContainer",defaultTheme:b});const W=function(e={}){const{createStyledComponent:r=f,useThemeProps:m=g,componentName:p="MuiContainer"}=e,x=r(({theme:e,ownerState:a})=>t({width:"100%",marginLeft:"auto",boxSizing:"border-box",marginRight:"auto",display:"block"},!a.disableGutters&&{paddingLeft:e.spacing(2),paddingRight:e.spacing(2),[e.breakpoints.up("sm")]:{paddingLeft:e.spacing(3),paddingRight:e.spacing(3)}}),({theme:e,ownerState:t})=>t.fixed&&Object.keys(e.breakpoints.values).reduce((t,a)=>{const s=a,i=e.breakpoints.values[s];return 0!==i&&(t[e.breakpoints.up(s)]={maxWidth:`${i}${e.breakpoints.unit}`}),t},{}),({theme:e,ownerState:a})=>t({},"xs"===a.maxWidth&&{[e.breakpoints.up("xs")]:{maxWidth:Math.max(e.breakpoints.values.xs,444)}},a.maxWidth&&"xs"!==a.maxWidth&&{[e.breakpoints.up(a.maxWidth)]:{maxWidth:`${e.breakpoints.values[a.maxWidth]}${e.breakpoints.unit}`}}));return a.forwardRef(function(e,a){const r=m(e),{className:c,component:h="div",disableGutters:b=!1,fixed:f=!1,maxWidth:g="lg"}=r,W=s(r,l),k=t({},r,{component:h,disableGutters:b,fixed:f,maxWidth:g}),S=((e,t)=>{const{classes:a,fixed:s,disableGutters:i,maxWidth:n}=e,r={root:["root",n&&`maxWidth${o(String(n))}`,s&&"fixed",i&&"disableGutters"]};return d(r,e=>u(t,e),a)})(k,p);return i(x,t({as:h,ownerState:k,className:n(S.root,c),ref:a},W))})}({createStyledComponent:x("div",{name:"MuiContainer",slot:"Root",overridesResolver:(e,t)=>{const{ownerState:a}=e;return[t.root,t[`maxWidth${o(String(a.maxWidth))}`],a.fixed&&t.fixed,a.disableGutters&&t.disableGutters]}}),useThemeProps:e=>p({props:e,name:"MuiContainer"})}),k=c(i("path",{d:"M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"}),"Refresh");export{W as C,k as R};
@@ -1 +1 @@
1
- import{c as a,f as e,an as t,B as o,S as r,a8 as n,T as i,G as c,C as s,F as l,a9 as d,P as h,ac as p,ap as u,aq as w,a1 as v,j as b,i as f,a2 as x,z as g,a7 as y,q as m,Z as S,ao as L,D as k,I as z}from"./index-3gnGrSPi.js";import{C as H,R as j}from"./Refresh-_yMWRw_x.js";import{K as C}from"./KeyboardArrowLeft-wYBUTbRV.js";const A=a(e("path",{d:"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"}),"Article"),R=a(e("path",{d:"M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"}),"BugReport"),M=a(e("path",{d:"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"}),"Search"),B=a=>{const t={color:"white",fontSize:28};switch(a.type){case"debug":return e(R,{sx:t});case"info":return e(u,{sx:t});case"warn":return e(p,{sx:t});default:return e(A,{sx:t})}},D=t.virtualize(({data:a,sx:t})=>{const p=(a=>{switch(a.type){case"debug":default:return"#9E9E9E";case"info":return"#2196F3";case"warn":return"#FF9800";case"log":return"#4CAF50"}})(a);return e(h,{variant:"outlined",sx:{display:"flex",alignItems:"stretch",justifyContent:"stretch",...t},children:e(o,{sx:{flex:1,position:"relative",overflow:"hidden",height:"100%",width:"100%",borderRadius:"12px"},children:[e(r,{direction:"row",spacing:2,sx:{p:2},children:[e(n,{sx:{width:56,height:56,background:p},children:B(a)}),e(r,{flex:1,spacing:1,children:[e(r,{direction:"row",justifyContent:"space-between",alignItems:"flex-start",children:[e(i,{variant:"h6",sx:{fontWeight:600,wordBreak:"break-all"},children:a.topic}),e(i,{variant:"body2",color:"text.secondary",sx:{whiteSpace:"nowrap",ml:2},children:c(a.createdAt).format("HH:mm DD/MM/YYYY")})]}),e(r,{direction:"row",spacing:1,flexWrap:"wrap",children:e(s,{size:"small",label:a.type.toUpperCase(),sx:{background:p,color:"white",fontWeight:500}})}),a.args.length>0&&e(l,{children:[e(d,{sx:{my:1}}),e(o,{component:"pre",sx:{m:0,fontSize:"0.75rem",whiteSpace:"pre-wrap",wordBreak:"break-all",color:"text.secondary"},children:JSON.stringify(1===a.args.length?a.args[0]:a.args,null,2)})]})]})]}),e(o,{sx:{position:"absolute",top:0,left:0,bottom:0,width:6,zIndex:1,background:p}})]})})}),E=[{action:"download-action",label:"Download",icon:()=>e(z,{icon:k,color:"#4caf50"})},{divider:!0},{action:"update-now",label:"Refresh manually",icon:()=>e(z,{icon:j,color:"#4caf50"})}],F=[{type:S.Link,action:"back-action",label:e(C,{sx:{display:"block"}})},{type:S.Link,action:"back-action",label:"Main"},{type:S.Link,action:"back-action",label:"Logs"},{type:S.Button,icon:M,action:"search-action",label:"Search"}],I=new b,V=()=>{const[a,o]=w(""),{data:r,hasMore:n,loading:i,onSkip:c}=v({handler:async(e,t)=>{const o=await f.logViewService.getList(),r=x(e,t);for(const n of o)if(new RegExp(a.current,"i").test(n.topic)&&r([n]).done)break;return r().rows},onLoadStart:()=>f.layoutService.setAppbarLoader(!0),onLoadEnd:()=>f.layoutService.setAppbarLoader(!1),reloadSubject:I}),s=g(r),{execute:l}=y(async()=>{const a=new Blob([JSON.stringify(s.current,null,2)],{type:"application/json"}),e=URL.createObjectURL(a);f.layoutService.downloadFile(e,`logs_${Date.now()}.json`)},{onLoadStart:()=>f.layoutService.setAppbarLoader(!0),onLoadEnd:()=>f.layoutService.setAppbarLoader(!1)});return e(H,{children:[e(m,{items:F,actions:E,onAction:async a=>{"back-action"===a&&f.routerService.push("/"),"download-action"===a&&l(),"update-now"===a&&(o(""),await I.next()),"search-action"===a&&(async()=>{const a=await f.layoutService.prompt("Search keyword");if(a)return o(a),void I.next();o(""),I.next()})()}}),e(t,{sx:{height:"calc(100vh - 155px)"},withScrollbar:!0,minHeight:72,loading:i,onDataRequest:c,bufferSize:L,hasMore:n,children:r.map(a=>e(D,{data:a,sx:{mb:1}},a.id))})]})};export{V as LogPage,V as default};
1
+ import{c as a,f as e,an as t,B as o,S as r,a8 as n,T as i,G as c,C as s,F as l,a9 as d,P as h,ac as p,ap as u,aq as w,a1 as v,j as b,i as f,a2 as x,z as g,a7 as y,q as m,Z as S,ao as L,D as k,I as z}from"./index-CBPue3Jb.js";import{C as H,R as j}from"./Refresh-DFUXqFNa.js";import{K as C}from"./KeyboardArrowLeft-D-vyob5u.js";const A=a(e("path",{d:"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 14H7v-2h7v2zm3-4H7v-2h10v2zm0-4H7V7h10v2z"}),"Article"),R=a(e("path",{d:"M20 8h-2.81c-.45-.78-1.07-1.45-1.82-1.96L17 4.41 15.59 3l-2.17 2.17C12.96 5.06 12.49 5 12 5c-.49 0-.96.06-1.41.17L8.41 3 7 4.41l1.62 1.63C7.88 6.55 7.26 7.22 6.81 8H4v2h2.09c-.05.33-.09.66-.09 1v1H4v2h2v1c0 .34.04.67.09 1H4v2h2.81c1.04 1.79 2.97 3 5.19 3s4.15-1.21 5.19-3H20v-2h-2.09c.05-.33.09-.66.09-1v-1h2v-2h-2v-1c0-.34-.04-.67-.09-1H20V8zm-6 8h-4v-2h4v2zm0-4h-4v-2h4v2z"}),"BugReport"),M=a(e("path",{d:"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"}),"Search"),B=a=>{const t={color:"white",fontSize:28};switch(a.type){case"debug":return e(R,{sx:t});case"info":return e(u,{sx:t});case"warn":return e(p,{sx:t});default:return e(A,{sx:t})}},D=t.virtualize(({data:a,sx:t})=>{const p=(a=>{switch(a.type){case"debug":default:return"#9E9E9E";case"info":return"#2196F3";case"warn":return"#FF9800";case"log":return"#4CAF50"}})(a);return e(h,{variant:"outlined",sx:{display:"flex",alignItems:"stretch",justifyContent:"stretch",...t},children:e(o,{sx:{flex:1,position:"relative",overflow:"hidden",height:"100%",width:"100%",borderRadius:"12px"},children:[e(r,{direction:"row",spacing:2,sx:{p:2},children:[e(n,{sx:{width:56,height:56,background:p},children:B(a)}),e(r,{flex:1,spacing:1,children:[e(r,{direction:"row",justifyContent:"space-between",alignItems:"flex-start",children:[e(i,{variant:"h6",sx:{fontWeight:600,wordBreak:"break-all"},children:a.topic}),e(i,{variant:"body2",color:"text.secondary",sx:{whiteSpace:"nowrap",ml:2},children:c(a.createdAt).format("HH:mm DD/MM/YYYY")})]}),e(r,{direction:"row",spacing:1,flexWrap:"wrap",children:e(s,{size:"small",label:a.type.toUpperCase(),sx:{background:p,color:"white",fontWeight:500}})}),a.args.length>0&&e(l,{children:[e(d,{sx:{my:1}}),e(o,{component:"pre",sx:{m:0,fontSize:"0.75rem",whiteSpace:"pre-wrap",wordBreak:"break-all",color:"text.secondary"},children:JSON.stringify(1===a.args.length?a.args[0]:a.args,null,2)})]})]})]}),e(o,{sx:{position:"absolute",top:0,left:0,bottom:0,width:6,zIndex:1,background:p}})]})})}),E=[{action:"download-action",label:"Download",icon:()=>e(z,{icon:k,color:"#4caf50"})},{divider:!0},{action:"update-now",label:"Refresh manually",icon:()=>e(z,{icon:j,color:"#4caf50"})}],F=[{type:S.Link,action:"back-action",label:e(C,{sx:{display:"block"}})},{type:S.Link,action:"back-action",label:"Main"},{type:S.Link,action:"back-action",label:"Logs"},{type:S.Button,icon:M,action:"search-action",label:"Search"}],I=new b,V=()=>{const[a,o]=w(""),{data:r,hasMore:n,loading:i,onSkip:c}=v({handler:async(e,t)=>{const o=await f.logViewService.getList(),r=x(e,t);for(const n of o)if(new RegExp(a.current,"i").test(n.topic)&&r([n]).done)break;return r().rows},onLoadStart:()=>f.layoutService.setAppbarLoader(!0),onLoadEnd:()=>f.layoutService.setAppbarLoader(!1),reloadSubject:I}),s=g(r),{execute:l}=y(async()=>{const a=new Blob([JSON.stringify(s.current,null,2)],{type:"application/json"}),e=URL.createObjectURL(a);f.layoutService.downloadFile(e,`logs_${Date.now()}.json`)},{onLoadStart:()=>f.layoutService.setAppbarLoader(!0),onLoadEnd:()=>f.layoutService.setAppbarLoader(!1)});return e(H,{children:[e(m,{items:F,actions:E,onAction:async a=>{"back-action"===a&&f.routerService.push("/"),"download-action"===a&&l(),"update-now"===a&&(o(""),await I.next()),"search-action"===a&&(async()=>{const a=await f.layoutService.prompt("Search keyword");if(a)return o(a),void I.next();o(""),I.next()})()}}),e(t,{sx:{height:"calc(100vh - 155px)"},withScrollbar:!0,minHeight:72,loading:i,onDataRequest:c,bufferSize:L,hasMore:n,children:r.map(a=>e(D,{data:a,sx:{mb:1}},a.id))})]})};export{V as LogPage,V as default};
@@ -1 +1 @@
1
- import{r as e,f as a,P as i,B as r,S as n,a8 as t,T as s,G as l,C as o,_ as c,F as p,a9 as d,aa as m,ab as u,ac as b,ad as v,ae as y,af as g,a6 as h,ag as k,ah as $,ai as f,aj as x,ak as S,al as _,am as C,i as P,a1 as w,j as L,a2 as A,q as z,Z as O,an as j,ao as E,I as F}from"./index-3gnGrSPi.js";import{C as T,R}from"./Refresh-_yMWRw_x.js";import{K as B}from"./KeyboardArrowLeft-wYBUTbRV.js";const U=e=>{const i={color:"white",fontSize:28};switch(e.type){case"signal.opened":case"partial_profit.available":case"partial_profit.commit":return a(S,{sx:i});case"signal.closed":case"signal_sync.close":return a(h,{sx:i});case"signal.scheduled":return a(C,{sx:i});case"signal.cancelled":return a(_,{sx:i});case"partial_loss.available":case"partial_loss.commit":case"average_buy.commit":return a(f,{sx:i});case"breakeven.available":case"breakeven.commit":return a(x,{sx:i});case"activate_scheduled.commit":case"signal_sync.open":return a(k,{sx:i});case"trailing_stop.commit":case"trailing_take.commit":return a($,{sx:i});case"risk.rejection":return a(g,{sx:i});case"error.info":case"error.validation":return a(y,{sx:i});case"error.critical":return a(v,{sx:i});default:return a(b,{sx:i})}},D=e=>{switch(e.type){case"signal.opened":return`${c("Opened")} ${e.position.toUpperCase()} ${e.symbol}`;case"signal.closed":return`${c("Closed")} ${e.symbol} (${e.pnlPercentage>0?"+":""}${e.pnlPercentage.toFixed(2)}%)`;case"signal.scheduled":return`${c("Scheduled")} ${e.position.toUpperCase()} ${e.symbol}`;case"signal.cancelled":return`${c("Cancelled")} ${e.symbol}`;case"partial_profit.available":return`${c("Partial profit")} ${e.level}% ${e.symbol}`;case"partial_profit.commit":return`${c("Profit fixed")} ${e.percentToClose}% ${e.symbol}`;case"partial_loss.available":return`${c("Partial loss")} ${e.level}% ${e.symbol}`;case"partial_loss.commit":return`${c("Loss fixed")} ${e.percentToClose}% ${e.symbol}`;case"breakeven.available":return`${c("Breakeven available")} ${e.symbol}`;case"breakeven.commit":return`${c("Breakeven set")} ${e.symbol}`;case"activate_scheduled.commit":return`${c("Activated")} ${e.position.toUpperCase()} ${e.symbol}`;case"average_buy.commit":return`${c("Average Buy")} ${e.symbol}`;case"trailing_stop.commit":return`${c("Trailing stop")} ${e.symbol}`;case"trailing_take.commit":return`${c("Trailing take")} ${e.symbol}`;case"signal_sync.open":return`${c("Sync Open")} ${e.position.toUpperCase()} ${e.symbol}`;case"signal_sync.close":return`${c("Sync Close")} ${e.symbol} (${e.pnlPercentage>0?"+":""}${e.pnlPercentage.toFixed(2)}%)`;case"risk.rejection":return`${c("Rejected")} ${e.position.toUpperCase()} ${e.symbol}`;case"error.info":return`${c("Error")}: ${e.message}`;case"error.validation":return`${c("Validation")}: ${e.message}`;case"error.critical":return`${c("Critical")}: ${e.message}`;default:return c("Unknown")}},W=e=>{switch(e.type){case"signal.opened":return c("Signal Opened");case"signal.closed":return c("Signal Closed");case"signal.scheduled":return c("Signal Scheduled");case"signal.cancelled":return c("Signal Cancelled");case"partial_profit.available":return c("Partial Profit Available");case"partial_profit.commit":return c("Partial Profit Commit");case"partial_loss.available":return c("Partial Loss Available");case"partial_loss.commit":return c("Partial Loss Commit");case"breakeven.available":return c("Breakeven Available");case"breakeven.commit":return c("Breakeven Commit");case"activate_scheduled.commit":return c("Activated Scheduled");case"average_buy.commit":return c("Average Buy");case"trailing_stop.commit":return c("Trailing Stop");case"trailing_take.commit":return c("Trailing Take");case"signal_sync.open":return c("Signal Sync Open");case"signal_sync.close":return c("Signal Sync Close");case"risk.rejection":return c("Risk Rejection");case"error.info":return c("Info Error");case"error.validation":return c("Validation Error");case"error.critical":return c("Critical Error");default:return c("Unknown")}},I=e=>"symbol"in e,M=e=>"position"in e,N=e=>"priceOpen"in e&&"priceTakeProfit"in e&&"priceStopLoss"in e,Y=e=>"pnlPercentage"in e,H=e=>"level"in e,V=e=>"percentToClose"in e,q=e=>"currentPrice"in e,K=e=>"duration"in e,G=e=>"closeReason"in e,Z=e=>"cancelReason"in e,J=e=>"priceClose"in e,Q=e=>"percentShift"in e,X=e=>"note"in e&&!!e.note,ee=e=>"message"in e,ae=e=>"rejectionNote"in e,ie=e=>"activePositionCount"in e,re=e=>"effectivePriceOpen"in e,ne=e=>"totalEntries"in e&&e.totalEntries>1,te=e=>"originalPriceOpen"in e&&"priceOpen"in e&&e.originalPriceOpen!==e.priceOpen,se=e=>"totalPartials"in e&&e.totalPartials>0,le=e=>"cost"in e,oe=e=>"pnlPriceOpen"in e&&"pnlPriceClose"in e&&"pnlCost"in e&&"pnlEntries"in e,ce=e.forwardRef(({item:e,className:b,style:v,sx:y},g)=>{const h=(e=>{switch(e.type){case"signal.opened":case"activate_scheduled.commit":case"signal_sync.open":return"#4CAF50";case"signal.closed":case"signal_sync.close":return"#2196F3";case"signal.scheduled":case"average_buy.commit":case"error.info":case"error.validation":return"#FF9800";case"signal.cancelled":default:return"#9E9E9E";case"partial_profit.available":case"partial_profit.commit":return"#8BC34A";case"partial_loss.available":case"partial_loss.commit":return"#FF5722";case"breakeven.available":case"breakeven.commit":return"#00BCD4";case"trailing_stop.commit":case"trailing_take.commit":return"#673AB7";case"risk.rejection":return"#F44336";case"error.critical":return"#D32F2F"}})(e),k=(e=>"timestamp"in e)(e)?e.timestamp:Date.now();return a("div",{className:b,style:v,ref:g,children:a(i,{variant:"outlined",onClick:()=>(e=>{switch(e.type){case"risk.rejection":P.layoutService.pickRisk(e.id);break;case"signal.opened":P.layoutService.pickSignalOpened(e.id);break;case"signal.closed":P.layoutService.pickSignalClosed(e.id);break;case"signal.scheduled":P.layoutService.pickSignalScheduled(e.id);break;case"signal.cancelled":P.layoutService.pickSignalCancelled(e.id);break;case"partial_profit.available":P.layoutService.pickPartialProfitAvailable(e.id);break;case"partial_profit.commit":P.layoutService.pickPartialProfitCommit(e.id);break;case"partial_loss.available":P.layoutService.pickPartialLossAvailable(e.id);break;case"partial_loss.commit":P.layoutService.pickPartialLossCommit(e.id);break;case"breakeven.available":P.layoutService.pickBreakevenAvailable(e.id);break;case"breakeven.commit":P.layoutService.pickBreakevenCommit(e.id);break;case"trailing_stop.commit":P.layoutService.pickTrailingStop(e.id);break;case"trailing_take.commit":P.layoutService.pickTrailingTake(e.id);break;case"activate_scheduled.commit":P.layoutService.pickActivateScheduled(e.id);break;case"average_buy.commit":P.layoutService.pickAverageBuyCommit(e.id);break;case"signal_sync.open":P.layoutService.pickSignalSyncOpen(e.id);break;case"signal_sync.close":P.layoutService.pickSignalSyncClose(e.id)}})(e),sx:{transition:"box-shadow 0.2s ease",cursor:"pointer",display:"flex",alignItems:"stretch",justifyContent:"stretch","&:hover":{boxShadow:4},...y},children:a(r,{sx:{flex:1,position:"relative",overflow:"hidden",height:"100%",width:"100%",borderRadius:"12px"},children:[a(n,{direction:"row",spacing:2,sx:{p:2},children:[a(t,{sx:{width:56,height:56,background:h},children:U(e)}),a(n,{flex:1,spacing:1,children:[a(n,{direction:"row",justifyContent:"space-between",alignItems:"flex-start",children:[a(s,{variant:"h6",sx:{fontWeight:600},children:D(e)}),a(s,{variant:"body2",color:"text.secondary",sx:{whiteSpace:"nowrap",ml:2},children:l(k).format("HH:mm DD/MM/YYYY")})]}),a(n,{direction:"row",spacing:1,flexWrap:"wrap",children:[a(o,{size:"small",label:W(e),sx:{background:h,color:"white",fontWeight:500}}),I(e)&&a(o,{size:"small",label:e.symbol,variant:"outlined"}),M(e)&&a(o,{size:"small",label:e.position.toUpperCase(),variant:"outlined",color:"long"===e.position?"success":"error"}),Y(e)&&a(o,{size:"small",label:`PnL: ${e.pnlPercentage>0?"+":""}${e.pnlPercentage.toFixed(2)}%`,color:e.pnlPercentage>=0?"success":"error",variant:"outlined"}),H(e)&&a(o,{size:"small",label:`${c("Level")}: ${e.level}%`,variant:"outlined"}),V(e)&&a(o,{size:"small",label:`${c("Close")}: ${e.percentToClose}%`,variant:"outlined"}),K(e)&&a(o,{size:"small",label:`${c("Duration")}: ${e.duration} ${c("min")}`,variant:"outlined"}),G(e)&&a(o,{size:"small",label:e.closeReason,variant:"outlined",color:"info"}),Z(e)&&a(o,{size:"small",label:e.cancelReason,variant:"outlined",color:"info"}),Q(e)&&a(o,{size:"small",label:`${c("Shift")}: ${e.percentShift>0?"+":""}${e.percentShift}%`,variant:"outlined"}),ie(e)&&a(o,{size:"small",label:`${c("Active")}: ${e.activePositionCount}`,variant:"outlined"}),ne(e)&&a(o,{size:"small",label:`${c("Entries")}: ${e.totalEntries}`,variant:"outlined"}),se(e)&&a(o,{size:"small",label:`${c("Partials")}: ${e.totalPartials}`,variant:"outlined"}),le(e)&&a(o,{size:"small",label:`${c("Cost")}: ${e.cost.toFixed(2)}$`,variant:"outlined"}),re(e)&&a(o,{size:"small",label:`${c("Avg entry")}: ${e.effectivePriceOpen}`,variant:"outlined",color:"warning"}),te(e)&&a(o,{size:"small",label:`${c("Orig entry")}: ${e.originalPriceOpen}`,variant:"outlined"})]}),N(e)&&a(p,{children:[a(d,{sx:{my:1}}),a(n,{direction:"row",spacing:3,flexWrap:"wrap",children:[a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Entry"),":"," "]}),e.priceOpen]}),J(e)&&a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Close"),":"," "]}),e.priceClose]}),q(e)&&a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Current"),":"," "]}),e.currentPrice]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Take Profit"),":"," "]}),e.priceTakeProfit]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Stop Loss"),":"," "]}),e.priceStopLoss]})]})]}),oe(e)&&a(p,{children:[a(d,{sx:{my:1}}),a(n,{direction:"row",spacing:3,flexWrap:"wrap",children:[a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("PnL Entry"),":"," "]}),e.pnlPriceOpen]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("PnL Exit"),":"," "]}),e.pnlPriceClose]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("PnL"),":"," "]}),a(s,{component:"span",color:e.pnlCost>=0?"success.main":"error.main",children:[e.pnlCost>=0?"+":"",e.pnlCost.toFixed(2),"$"]})]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Invested"),":"," "]}),e.pnlEntries.toFixed(2),"$"]})]})]})]})]}),X(e)&&a(r,{sx:{px:2,pb:2},children:[a(d,{sx:{mb:1.5}}),a(r,{component:"pre",sx:{m:0,whiteSpace:"pre-wrap",wordWrap:"break-word"},children:a(m,{style:{textWrap:"wrap"},config:u,handler:()=>e.note})})]}),ae(e)&&a(r,{sx:{px:2,pb:2},children:[a(d,{sx:{mb:1.5}}),a(s,{variant:"body2",color:"error",children:e.rejectionNote})]}),ee(e)&&!X(e)&&a(r,{sx:{px:2,pb:2},children:[a(d,{sx:{mb:1.5}}),a(s,{variant:"body2",color:"text.secondary",children:e.message})]}),a(r,{sx:{position:"absolute",top:0,left:0,bottom:0,width:6,zIndex:1,background:h}})]})})})}),pe=[{action:"update-now",label:"Refresh manually",icon:()=>a(F,{icon:R,color:"#4caf50"})}],de=[{type:O.Link,action:"back-action",label:a(B,{sx:{display:"block"}})},{type:O.Link,action:"back-action",label:"Main"},{type:O.Link,action:"back-action",label:"Notifications"}],me=new L,ue=()=>{const{data:e,hasMore:i,loading:r,onSkip:n}=w({handler:async(e,a)=>{const i=await P.notificationViewService.getList(),r=A(e,a);for(const n of i)if(r([n]).done)break;return r().rows},onLoadStart:()=>P.layoutService.setAppbarLoader(!0),onLoadEnd:()=>P.layoutService.setAppbarLoader(!1),reloadSubject:me});return a(T,{children:[a(z,{items:de,actions:pe,onAction:async e=>{"back-action"===e&&P.routerService.push("/"),"update-now"===e&&await me.next()}}),a(j,{sx:{height:"calc(100vh - 155px)"},withScrollbar:!0,minHeight:72,loading:r,onDataRequest:n,bufferSize:E,hasMore:i,children:e.map(e=>a(ce,{item:e,sx:{mb:1}},e.id))})]})};export{ue as NotificationPage,ue as default};
1
+ import{r as e,f as a,P as i,B as r,S as n,a8 as t,T as s,G as l,C as o,_ as c,F as p,a9 as d,aa as m,ab as u,ac as b,ad as v,ae as y,af as g,a6 as h,ag as k,ah as $,ai as f,aj as x,ak as S,al as _,am as C,i as P,a1 as w,j as L,a2 as A,q as z,Z as O,an as j,ao as E,I as F}from"./index-CBPue3Jb.js";import{C as T,R}from"./Refresh-DFUXqFNa.js";import{K as B}from"./KeyboardArrowLeft-D-vyob5u.js";const U=e=>{const i={color:"white",fontSize:28};switch(e.type){case"signal.opened":case"partial_profit.available":case"partial_profit.commit":return a(S,{sx:i});case"signal.closed":case"signal_sync.close":return a(h,{sx:i});case"signal.scheduled":return a(C,{sx:i});case"signal.cancelled":return a(_,{sx:i});case"partial_loss.available":case"partial_loss.commit":case"average_buy.commit":return a(f,{sx:i});case"breakeven.available":case"breakeven.commit":return a(x,{sx:i});case"activate_scheduled.commit":case"signal_sync.open":return a(k,{sx:i});case"trailing_stop.commit":case"trailing_take.commit":return a($,{sx:i});case"risk.rejection":return a(g,{sx:i});case"error.info":case"error.validation":return a(y,{sx:i});case"error.critical":return a(v,{sx:i});default:return a(b,{sx:i})}},D=e=>{switch(e.type){case"signal.opened":return`${c("Opened")} ${e.position.toUpperCase()} ${e.symbol}`;case"signal.closed":return`${c("Closed")} ${e.symbol} (${e.pnlPercentage>0?"+":""}${e.pnlPercentage.toFixed(2)}%)`;case"signal.scheduled":return`${c("Scheduled")} ${e.position.toUpperCase()} ${e.symbol}`;case"signal.cancelled":return`${c("Cancelled")} ${e.symbol}`;case"partial_profit.available":return`${c("Partial profit")} ${e.level}% ${e.symbol}`;case"partial_profit.commit":return`${c("Profit fixed")} ${e.percentToClose}% ${e.symbol}`;case"partial_loss.available":return`${c("Partial loss")} ${e.level}% ${e.symbol}`;case"partial_loss.commit":return`${c("Loss fixed")} ${e.percentToClose}% ${e.symbol}`;case"breakeven.available":return`${c("Breakeven available")} ${e.symbol}`;case"breakeven.commit":return`${c("Breakeven set")} ${e.symbol}`;case"activate_scheduled.commit":return`${c("Activated")} ${e.position.toUpperCase()} ${e.symbol}`;case"average_buy.commit":return`${c("Average Buy")} ${e.symbol}`;case"trailing_stop.commit":return`${c("Trailing stop")} ${e.symbol}`;case"trailing_take.commit":return`${c("Trailing take")} ${e.symbol}`;case"signal_sync.open":return`${c("Sync Open")} ${e.position.toUpperCase()} ${e.symbol}`;case"signal_sync.close":return`${c("Sync Close")} ${e.symbol} (${e.pnlPercentage>0?"+":""}${e.pnlPercentage.toFixed(2)}%)`;case"risk.rejection":return`${c("Rejected")} ${e.position.toUpperCase()} ${e.symbol}`;case"error.info":return`${c("Error")}: ${e.message}`;case"error.validation":return`${c("Validation")}: ${e.message}`;case"error.critical":return`${c("Critical")}: ${e.message}`;default:return c("Unknown")}},W=e=>{switch(e.type){case"signal.opened":return c("Signal Opened");case"signal.closed":return c("Signal Closed");case"signal.scheduled":return c("Signal Scheduled");case"signal.cancelled":return c("Signal Cancelled");case"partial_profit.available":return c("Partial Profit Available");case"partial_profit.commit":return c("Partial Profit Commit");case"partial_loss.available":return c("Partial Loss Available");case"partial_loss.commit":return c("Partial Loss Commit");case"breakeven.available":return c("Breakeven Available");case"breakeven.commit":return c("Breakeven Commit");case"activate_scheduled.commit":return c("Activated Scheduled");case"average_buy.commit":return c("Average Buy");case"trailing_stop.commit":return c("Trailing Stop");case"trailing_take.commit":return c("Trailing Take");case"signal_sync.open":return c("Signal Sync Open");case"signal_sync.close":return c("Signal Sync Close");case"risk.rejection":return c("Risk Rejection");case"error.info":return c("Info Error");case"error.validation":return c("Validation Error");case"error.critical":return c("Critical Error");default:return c("Unknown")}},I=e=>"symbol"in e,M=e=>"position"in e,N=e=>"priceOpen"in e&&"priceTakeProfit"in e&&"priceStopLoss"in e,Y=e=>"pnlPercentage"in e,H=e=>"level"in e,V=e=>"percentToClose"in e,q=e=>"currentPrice"in e,K=e=>"duration"in e,G=e=>"closeReason"in e,Z=e=>"cancelReason"in e,J=e=>"priceClose"in e,Q=e=>"percentShift"in e,X=e=>"note"in e&&!!e.note,ee=e=>"message"in e,ae=e=>"rejectionNote"in e,ie=e=>"activePositionCount"in e,re=e=>"effectivePriceOpen"in e,ne=e=>"totalEntries"in e&&e.totalEntries>1,te=e=>"originalPriceOpen"in e&&"priceOpen"in e&&e.originalPriceOpen!==e.priceOpen,se=e=>"totalPartials"in e&&e.totalPartials>0,le=e=>"cost"in e,oe=e=>"pnlPriceOpen"in e&&"pnlPriceClose"in e&&"pnlCost"in e&&"pnlEntries"in e,ce=e.forwardRef(({item:e,className:b,style:v,sx:y},g)=>{const h=(e=>{switch(e.type){case"signal.opened":case"activate_scheduled.commit":case"signal_sync.open":return"#4CAF50";case"signal.closed":case"signal_sync.close":return"#2196F3";case"signal.scheduled":case"average_buy.commit":case"error.info":case"error.validation":return"#FF9800";case"signal.cancelled":default:return"#9E9E9E";case"partial_profit.available":case"partial_profit.commit":return"#8BC34A";case"partial_loss.available":case"partial_loss.commit":return"#FF5722";case"breakeven.available":case"breakeven.commit":return"#00BCD4";case"trailing_stop.commit":case"trailing_take.commit":return"#673AB7";case"risk.rejection":return"#F44336";case"error.critical":return"#D32F2F"}})(e),k=(e=>"timestamp"in e)(e)?e.timestamp:Date.now();return a("div",{className:b,style:v,ref:g,children:a(i,{variant:"outlined",onClick:()=>(e=>{switch(e.type){case"risk.rejection":P.layoutService.pickRisk(e.id);break;case"signal.opened":P.layoutService.pickSignalOpened(e.id);break;case"signal.closed":P.layoutService.pickSignalClosed(e.id);break;case"signal.scheduled":P.layoutService.pickSignalScheduled(e.id);break;case"signal.cancelled":P.layoutService.pickSignalCancelled(e.id);break;case"partial_profit.available":P.layoutService.pickPartialProfitAvailable(e.id);break;case"partial_profit.commit":P.layoutService.pickPartialProfitCommit(e.id);break;case"partial_loss.available":P.layoutService.pickPartialLossAvailable(e.id);break;case"partial_loss.commit":P.layoutService.pickPartialLossCommit(e.id);break;case"breakeven.available":P.layoutService.pickBreakevenAvailable(e.id);break;case"breakeven.commit":P.layoutService.pickBreakevenCommit(e.id);break;case"trailing_stop.commit":P.layoutService.pickTrailingStop(e.id);break;case"trailing_take.commit":P.layoutService.pickTrailingTake(e.id);break;case"activate_scheduled.commit":P.layoutService.pickActivateScheduled(e.id);break;case"average_buy.commit":P.layoutService.pickAverageBuyCommit(e.id);break;case"signal_sync.open":P.layoutService.pickSignalSyncOpen(e.id);break;case"signal_sync.close":P.layoutService.pickSignalSyncClose(e.id)}})(e),sx:{transition:"box-shadow 0.2s ease",cursor:"pointer",display:"flex",alignItems:"stretch",justifyContent:"stretch","&:hover":{boxShadow:4},...y},children:a(r,{sx:{flex:1,position:"relative",overflow:"hidden",height:"100%",width:"100%",borderRadius:"12px"},children:[a(n,{direction:"row",spacing:2,sx:{p:2},children:[a(t,{sx:{width:56,height:56,background:h},children:U(e)}),a(n,{flex:1,spacing:1,children:[a(n,{direction:"row",justifyContent:"space-between",alignItems:"flex-start",children:[a(s,{variant:"h6",sx:{fontWeight:600},children:D(e)}),a(s,{variant:"body2",color:"text.secondary",sx:{whiteSpace:"nowrap",ml:2},children:l(k).format("HH:mm DD/MM/YYYY")})]}),a(n,{direction:"row",spacing:1,flexWrap:"wrap",children:[a(o,{size:"small",label:W(e),sx:{background:h,color:"white",fontWeight:500}}),I(e)&&a(o,{size:"small",label:e.symbol,variant:"outlined"}),M(e)&&a(o,{size:"small",label:e.position.toUpperCase(),variant:"outlined",color:"long"===e.position?"success":"error"}),Y(e)&&a(o,{size:"small",label:`PnL: ${e.pnlPercentage>0?"+":""}${e.pnlPercentage.toFixed(2)}%`,color:e.pnlPercentage>=0?"success":"error",variant:"outlined"}),H(e)&&a(o,{size:"small",label:`${c("Level")}: ${e.level}%`,variant:"outlined"}),V(e)&&a(o,{size:"small",label:`${c("Close")}: ${e.percentToClose}%`,variant:"outlined"}),K(e)&&a(o,{size:"small",label:`${c("Duration")}: ${e.duration} ${c("min")}`,variant:"outlined"}),G(e)&&a(o,{size:"small",label:e.closeReason,variant:"outlined",color:"info"}),Z(e)&&a(o,{size:"small",label:e.cancelReason,variant:"outlined",color:"info"}),Q(e)&&a(o,{size:"small",label:`${c("Shift")}: ${e.percentShift>0?"+":""}${e.percentShift}%`,variant:"outlined"}),ie(e)&&a(o,{size:"small",label:`${c("Active")}: ${e.activePositionCount}`,variant:"outlined"}),ne(e)&&a(o,{size:"small",label:`${c("Entries")}: ${e.totalEntries}`,variant:"outlined"}),se(e)&&a(o,{size:"small",label:`${c("Partials")}: ${e.totalPartials}`,variant:"outlined"}),le(e)&&a(o,{size:"small",label:`${c("Cost")}: ${e.cost.toFixed(2)}$`,variant:"outlined"}),re(e)&&a(o,{size:"small",label:`${c("Avg entry")}: ${e.effectivePriceOpen}`,variant:"outlined",color:"warning"}),te(e)&&a(o,{size:"small",label:`${c("Orig entry")}: ${e.originalPriceOpen}`,variant:"outlined"})]}),N(e)&&a(p,{children:[a(d,{sx:{my:1}}),a(n,{direction:"row",spacing:3,flexWrap:"wrap",children:[a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Entry"),":"," "]}),e.priceOpen]}),J(e)&&a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Close"),":"," "]}),e.priceClose]}),q(e)&&a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Current"),":"," "]}),e.currentPrice]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Take Profit"),":"," "]}),e.priceTakeProfit]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Stop Loss"),":"," "]}),e.priceStopLoss]})]})]}),oe(e)&&a(p,{children:[a(d,{sx:{my:1}}),a(n,{direction:"row",spacing:3,flexWrap:"wrap",children:[a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("PnL Entry"),":"," "]}),e.pnlPriceOpen]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("PnL Exit"),":"," "]}),e.pnlPriceClose]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("PnL"),":"," "]}),a(s,{component:"span",color:e.pnlCost>=0?"success.main":"error.main",children:[e.pnlCost>=0?"+":"",e.pnlCost.toFixed(2),"$"]})]}),a(s,{variant:"body2",children:[a(s,{component:"span",color:"text.secondary",children:[c("Invested"),":"," "]}),e.pnlEntries.toFixed(2),"$"]})]})]})]})]}),X(e)&&a(r,{sx:{px:2,pb:2},children:[a(d,{sx:{mb:1.5}}),a(r,{component:"pre",sx:{m:0,whiteSpace:"pre-wrap",wordWrap:"break-word"},children:a(m,{style:{textWrap:"wrap"},config:u,handler:()=>e.note})})]}),ae(e)&&a(r,{sx:{px:2,pb:2},children:[a(d,{sx:{mb:1.5}}),a(s,{variant:"body2",color:"error",children:e.rejectionNote})]}),ee(e)&&!X(e)&&a(r,{sx:{px:2,pb:2},children:[a(d,{sx:{mb:1.5}}),a(s,{variant:"body2",color:"text.secondary",children:e.message})]}),a(r,{sx:{position:"absolute",top:0,left:0,bottom:0,width:6,zIndex:1,background:h}})]})})})}),pe=[{action:"update-now",label:"Refresh manually",icon:()=>a(F,{icon:R,color:"#4caf50"})}],de=[{type:O.Link,action:"back-action",label:a(B,{sx:{display:"block"}})},{type:O.Link,action:"back-action",label:"Main"},{type:O.Link,action:"back-action",label:"Notifications"}],me=new L,ue=()=>{const{data:e,hasMore:i,loading:r,onSkip:n}=w({handler:async(e,a)=>{const i=await P.notificationViewService.getList(),r=A(e,a);for(const n of i)if(r([n]).done)break;return r().rows},onLoadStart:()=>P.layoutService.setAppbarLoader(!0),onLoadEnd:()=>P.layoutService.setAppbarLoader(!1),reloadSubject:me});return a(T,{children:[a(z,{items:de,actions:pe,onAction:async e=>{"back-action"===e&&P.routerService.push("/"),"update-now"===e&&await me.next()}}),a(j,{sx:{height:"calc(100vh - 155px)"},withScrollbar:!0,minHeight:72,loading:r,onDataRequest:n,bufferSize:E,hasMore:i,children:e.map(e=>a(ce,{item:e,sx:{mb:1}},e.id))})]})};export{ue as NotificationPage,ue as default};