Added Ledger, started removing Holdings

This commit is contained in:
Steve 2025-07-04 12:01:26 +01:00
parent e4f6c3d707
commit 5516aa1362
15 changed files with 2739 additions and 444 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,138 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "\\\\OZHOST1\\d$\\Documents\\Visual Studio Projects\\SharePrices\\", "WorkspaceRootPath": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\",
"Documents": [], "Documents": [
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\scripts\\shareprices.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\shareprices.aspx||{57312C73-6202-49E9-B1E1-40EA1A6DC1F6}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\shareprices.aspx||{57312C73-6202-49E9-B1E1-40EA1A6DC1F6}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\scripts\\shareprices_ledger.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices_ledger.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\scripts\\shareprices_holdings.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices_holdings.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|c:\\users\\tsuser\\sources\\repos\\steves_code\\websites\\shareprices\\shareprices\\sharepricesstyles.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\sharepricesstyles.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\scripts\\shareprices_accounts.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices_accounts.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\shareprices.aspx.vb||{2C015C70-C72C-11D0-88C3-00A0C9110049}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\shareprices.aspx.vb||{2C015C70-C72C-11D0-88C3-00A0C9110049}"
}
],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {
"Orientation": 0, "Orientation": 0,
"VerticalTabListWidth": 256, "VerticalTabListWidth": 256,
"DocumentGroups": [] "DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 6,
"Children": [
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "SharePricesStyles.css",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePricesStyles.css",
"RelativeDocumentMoniker": "SharePrices\\SharePricesStyles.css",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePricesStyles.css",
"RelativeToolTip": "SharePrices\\SharePricesStyles.css",
"ViewState": "AgIAAFYAAAAAAAAAAADgv2wAAAAHAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003000|",
"WhenOpened": "2025-05-15T16:16:53.007Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "SharePrices_Accounts.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Accounts.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices_Accounts.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Accounts.js",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices_Accounts.js",
"ViewState": "AgIAAPoAAAAAAAAAAAAAAPoAAAAeAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-05-12T12:30:52.565Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "SharePrices_Ledger.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Ledger.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices_Ledger.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Ledger.js*",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices_Ledger.js*",
"ViewState": "AgIAAEsAAACAmZmZmVklwG4AAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-05-11T19:04:49.08Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "SharePrices.aspx.vb",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx.vb",
"RelativeDocumentMoniker": "SharePrices\\SharePrices.aspx.vb",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx.vb",
"RelativeToolTip": "SharePrices\\SharePrices.aspx.vb",
"ViewState": "AgIAALUAAAAAAAAAAAAQwH4BAAA2AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003361|",
"WhenOpened": "2025-02-10T17:47:33.143Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "SharePrices_Holdings.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Holdings.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices_Holdings.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Holdings.js",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices_Holdings.js",
"ViewState": "AgIAAFIEAAAA8P////8BwMADAAAsAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-02-10T17:39:46.261Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "SharePrices.aspx",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx",
"RelativeDocumentMoniker": "SharePrices\\SharePrices.aspx",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx",
"RelativeToolTip": "SharePrices\\SharePrices.aspx",
"LogicalView": "7651a703-06e5-11d1-8ebd-00a0c90f26ea",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000195|",
"WhenOpened": "2025-01-06T10:39:09.87Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "SharePrices.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices.js",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices.js",
"ViewState": "AgIAADwAAADAZmZmZqYowEwBAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-01-06T10:28:28.952Z",
"EditorCaption": ""
}
]
}
]
} }
] ]
} }

View File

@ -1,12 +1,135 @@
{ {
"Version": 1, "Version": 1,
"WorkspaceRootPath": "C:\\Users\\Steve.OZDOMAIN\\source\\repos\\Steves_Code\\Websites\\SharePrices\\", "WorkspaceRootPath": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\",
"Documents": [], "Documents": [
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\scripts\\shareprices_holdings.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices_holdings.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\scripts\\shareprices_ledger.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices_ledger.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|c:\\users\\tsuser\\sources\\repos\\steves_code\\websites\\shareprices\\shareprices\\scripts\\shareprices.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\shareprices.aspx||{57312C73-6202-49E9-B1E1-40EA1A6DC1F6}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\shareprices.aspx||{57312C73-6202-49E9-B1E1-40EA1A6DC1F6}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\sharepricesstyles.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\sharepricesstyles.css||{A5401142-F49D-43DB-90B1-F57BA349E55C}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\scripts\\shareprices_accounts.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\scripts\\shareprices_accounts.js||{14D17961-FE51-464D-9111-C4AF11D7D99A}"
},
{
"AbsoluteMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\shareprices\\shareprices.aspx.vb||{2C015C70-C72C-11D0-88C3-00A0C9110049}",
"RelativeMoniker": "D:0:0:{AB459D42-2246-47E4-8F1B-F8325E8B780A}|SharePrices\\SharePrices.vbproj|solutionrelative:shareprices\\shareprices.aspx.vb||{2C015C70-C72C-11D0-88C3-00A0C9110049}"
}
],
"DocumentGroupContainers": [ "DocumentGroupContainers": [
{ {
"Orientation": 0, "Orientation": 0,
"VerticalTabListWidth": 256, "VerticalTabListWidth": 256,
"DocumentGroups": [] "DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 4,
"Children": [
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "SharePricesStyles.css",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePricesStyles.css",
"RelativeDocumentMoniker": "SharePrices\\SharePricesStyles.css",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePricesStyles.css",
"RelativeToolTip": "SharePrices\\SharePricesStyles.css",
"ViewState": "AgIAAFYAAAAAAAAAAADgv2wAAAAHAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003000|",
"WhenOpened": "2025-05-15T16:16:53.007Z"
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "SharePrices_Accounts.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Accounts.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices_Accounts.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Accounts.js",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices_Accounts.js",
"ViewState": "AgIAAPoAAAAAAAAAAAAAAPoAAAAeAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-05-12T12:30:52.565Z"
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "SharePrices_Ledger.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Ledger.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices_Ledger.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Ledger.js",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices_Ledger.js",
"ViewState": "AgIAAEsAAACAmZmZmVklwG4AAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-05-11T19:04:49.08Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 6,
"Title": "SharePrices.aspx.vb",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx.vb",
"RelativeDocumentMoniker": "SharePrices\\SharePrices.aspx.vb",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx.vb",
"RelativeToolTip": "SharePrices\\SharePrices.aspx.vb",
"ViewState": "AgIAALUAAAAAAAAAAAAQwH4BAAA2AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.003361|",
"WhenOpened": "2025-02-10T17:47:33.143Z"
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "SharePrices_Holdings.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Holdings.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices_Holdings.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices_Holdings.js",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices_Holdings.js",
"ViewState": "AgIAAJcEAAAAyAAAAEAgwLgEAAARAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-02-10T17:39:46.261Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "SharePrices.aspx",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx",
"RelativeDocumentMoniker": "SharePrices\\SharePrices.aspx",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\SharePrices.aspx",
"RelativeToolTip": "SharePrices\\SharePrices.aspx",
"LogicalView": "7651a703-06e5-11d1-8ebd-00a0c90f26ea",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000195|",
"WhenOpened": "2025-01-06T10:39:09.87Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "SharePrices.js",
"DocumentMoniker": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices.js",
"RelativeDocumentMoniker": "SharePrices\\scripts\\SharePrices.js",
"ToolTip": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\SharePrices\\scripts\\SharePrices.js",
"RelativeToolTip": "SharePrices\\scripts\\SharePrices.js",
"ViewState": "AgIAADwAAADAZmZmZqYowEwBAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001646|",
"WhenOpened": "2025-01-06T10:28:28.952Z",
"EditorCaption": ""
}
]
}
]
} }
] ]
} }

View File

@ -12,20 +12,36 @@ Public Class DataAccessLayer
Public Volume As Int64 Public Volume As Int64
End Class End Class
Public Shared Function GetInstruments() As String Public Shared Function GetInstruments() As String
Dim c As SqlCommand = GetSQLCommand("usp_GetInstruments") Dim c As SqlCommand = GetSQLCommand("usp_GetInstruments")
Dim Instruments As String = DataReaderToJSONString(c.ExecuteReader()) Dim Instruments As String = DataReaderToJSONString(c.ExecuteReader())
c = GetSQLCommand("usp_GetHoldings") c = GetSQLCommand("usp_GetHoldings")
Dim Holdings As String = DataReaderToJSONString(c.ExecuteReader()) Dim Holdings As String = DataReaderToJSONString(c.ExecuteReader())
c = GetSQLCommand("usp_GetHoldingsHistory") c = GetSQLCommand("usp_GetHoldingsHistory")
Dim HoldingsHistory As String = DataReaderToJSONString(c.ExecuteReader()) Dim HoldingsHistory As String = DataReaderToJSONString(c.ExecuteReader())
c = GetSQLCommand("usp_GetAccounts") c = GetSQLCommand("usp_GetAccounts")
Dim Accounts As String = DataReaderToJSONString(c.ExecuteReader()) Dim Accounts As String = DataReaderToJSONString(c.ExecuteReader())
GetInstruments = "{""Instruments"": " + Instruments + ", ""Holdings"": " + Holdings + ", ""HoldingsHistory"": " + HoldingsHistory + ", ""Accounts"": " + Accounts + "}" GetInstruments = "{""Instruments"": " + Instruments + ", ""Holdings"": " + Holdings + ", ""HoldingsHistory"": " + HoldingsHistory + ", ""Accounts"": " + Accounts + "}"
DisposeSQLCommand(c) DisposeSQLCommand(c)
End Function End Function
Public Shared Function AddInstrument(Symbol As String, FullName As String) As String Public Shared Function GetAggregatedCurrentHoldings() As String
Dim c As SqlCommand = GetSQLCommand("usp_GetAggregatedCurrentHoldings")
GetAggregatedCurrentHoldings = DataReaderToJSONString(c.ExecuteReader())
DisposeSQLCommand(c)
End Function
Public Shared Function GetCurrentHoldings() As String
Dim c As SqlCommand = GetSQLCommand("usp_GetCurrentHoldings")
GetCurrentHoldings = DataReaderToJSONString(c.ExecuteReader())
DisposeSQLCommand(c)
End Function
Public Shared Function GetTradeHistory() As String
Dim c As SqlCommand = GetSQLCommand("usp_GetTradeHistory")
GetTradeHistory = DataReaderToJSONString(c.ExecuteReader())
DisposeSQLCommand(c)
End Function
Public Shared Function AddInstrument(Symbol As String, FullName As String) As String
Dim c As SqlCommand = GetSQLCommand("usp_InsertInstrument") Dim c As SqlCommand = GetSQLCommand("usp_InsertInstrument")
c.Parameters.AddWithValue("Symbol", Symbol) c.Parameters.AddWithValue("Symbol", Symbol)
c.Parameters.AddWithValue("FullName", FullName) c.Parameters.AddWithValue("FullName", FullName)
@ -258,6 +274,7 @@ Public Class DataAccessLayer
Select Case dr.GetDataTypeName(fieldNo).ToUpper Select Case dr.GetDataTypeName(fieldNo).ToUpper
Case "CHAR", "VARCHAR" : thisRow += """" + dr(fieldNo) + """" Case "CHAR", "VARCHAR" : thisRow += """" + dr(fieldNo) + """"
Case "DATETIME", "SMALLDATETIME", "DATETIME2", "DATE" : thisRow += ToEpochTime(dr(fieldNo)).ToString() Case "DATETIME", "SMALLDATETIME", "DATETIME2", "DATE" : thisRow += ToEpochTime(dr(fieldNo)).ToString()
Case "BIT" : If (dr(fieldNo)) Then thisRow += "true" Else thisRow += "false"
Case Else : thisRow += dr(fieldNo).ToString() Case Else : thisRow += dr(fieldNo).ToString()
End Select End Select
End If End If

View File

@ -40,7 +40,8 @@
<a id="navCharts" class="activenav" onclick="showTab(this)" data-div="chartDiv">Charts</a> <a id="navCharts" class="activenav" onclick="showTab(this)" data-div="chartDiv">Charts</a>
<a id="navCurrentHoldings" onclick="showTab(this);" data-div="holdingsDiv">Holdings</a> <a id="navCurrentHoldings" onclick="showTab(this);" data-div="holdingsDiv">Holdings</a>
<a id="navAccounts" onclick="showTab(this);" data-div="accountsDiv">Accounts</a> <a id="navAccounts" onclick="showTab(this);" data-div="accountsDiv">Accounts</a>
<a id="navAnal" onclick="showTab(this);" data-div="analDiv">Analysis</a> <a id="navLedger" onclick="showTab(this); importedFunctions.updateLedgerTable();" data-div="ledgerDiv">Ledger</a>
<!--<a id="navAnal" onclick="showTab(this);" data-div="analDiv">Analysis</a>!-->
<a id="navHist" onclick="showTab(this); importedFunctions.refreshHistoryChart();" data-div="histDiv">History</a> <a id="navHist" onclick="showTab(this); importedFunctions.refreshHistoryChart();" data-div="histDiv">History</a>
<a id="navLog" onclick="showTab(this);" data-div="logDiv">Log</a> <a id="navLog" onclick="showTab(this);" data-div="logDiv">Log</a>
</td> </td>
@ -73,12 +74,26 @@
</div> </div>
<div class="tabParent"> <div class="tabParent">
<div class="tabContainer" id="holdingsDiv"> <div class="tabContainer" id="holdingsDiv">
<!-- Old holdings table
<div> <div>
<label for="groupBySymbol">Group By Symbol</label><input type="checkbox" name="groupBySymbol" id="groupBySymbol" onclick="handleClick(this)"/> <label for="groupBySymbol">Group By Symbol</label>
<input type="checkbox" name="groupBySymbol" id="groupBySymbol" onclick="handleClick(this)"/>
</div> </div>
<div id="holdingsTableDiv">Holdings table</div> <div id="holdingsTableDiv">Holdings table</div>
<br /> <br />
!-->
<div id="aggHoldingsTableDiv">Aggregated Holdings table</div>
<br />
<div>
<label for="showSubtotals">Show Tax Bracket Subtotals</label>
<input type="checkbox" name="showSubtotals" id="showSubtotals" onclick="handleClick(this)"/>
<label for="showCryptoHoldings">Show Cryptocurrency Holdings</label>
<input type="checkbox" name="showCryptoHoldings" id="showCryptoHoldings" onclick="handleClick(this)"/>
</div>
<div id="newHoldingsTableDiv">New Holdings table</div>
<br />
<div id="watchlistTableDiv">Watchlist table</div> <div id="watchlistTableDiv">Watchlist table</div>
<!-- Old pie charts
<br /> <br />
<table> <table>
<tr> <tr>
@ -91,6 +106,7 @@
<td>Current Value per Account<div id="divAccountValue" class="HoldingCurrenciesChart"></div></td> <td>Current Value per Account<div id="divAccountValue" class="HoldingCurrenciesChart"></div></td>
</tr> </tr>
</table> </table>
!-->
</div> </div>
</div> </div>
<div class="tabParent"> <div class="tabParent">
@ -101,9 +117,14 @@
<div id="accountsSummaryDiv"></div> <div id="accountsSummaryDiv"></div>
</div> </div>
</div> </div>
<div class="tabParent">
<div class="tabContainer" id="ledgerDiv">Analysis</div>
</div>
<!--
<div class="tabParent"> <div class="tabParent">
<div class="tabContainer" id="analDiv">Analysis</div> <div class="tabContainer" id="analDiv">Analysis</div>
</div> </div>
!-->
<div class="tabParent"> <div class="tabParent">
<div class="tabContainer" id="histDiv" style="height: 85%;">History Chart</div> <div class="tabContainer" id="histDiv" style="height: 85%;">History Chart</div>
<!--<span onclick="refreshHistoryChart();">Refresh Chart</span>!--> <!--<span onclick="refreshHistoryChart();">Refresh Chart</span>!-->
@ -141,6 +162,7 @@
<div id="chartTooltip" class="chart-tooltip"></div> <div id="chartTooltip" class="chart-tooltip"></div>
<script> <script>
let importedFunctions = {}; let importedFunctions = {};
function logInfo(msg) { function logInfo(msg) {
console.info(msg); console.info(msg);
if (typeof msg == 'object') { if (typeof msg == 'object') {
@ -202,6 +224,10 @@
break; break;
case 'hideEmptyAccounts': case 'hideEmptyAccounts':
break; break;
case 'showSubtotals':
break;
case 'showCryptoHoldings':
break;
} }
} }
</script> </script>
@ -209,7 +235,6 @@
import { import {
addInstrument, addInstrument,
createSharesTable, createSharesTable,
createSharesTableRow,
getInstruments, getInstruments,
redrawAllSharesCharts, redrawAllSharesCharts,
refreshHistoryChart, refreshHistoryChart,
@ -220,10 +245,12 @@
showModalDialog_FullScreenChart, showModalDialog_FullScreenChart,
showModalDialog_SoldHolding showModalDialog_SoldHolding
} from "./scripts/SharePrices.js"; } from "./scripts/SharePrices.js";
import { updateLedgerTable } from "./scripts/SharePrices_Ledger.js";
importedFunctions = { importedFunctions = {
addInstrument: addInstrument, addInstrument: addInstrument,
createSharesTable: createSharesTable, createSharesTable: createSharesTable,
createSharesTableRow: createSharesTableRow,
getInstruments: getInstruments, getInstruments: getInstruments,
redrawAllSharesCharts: redrawAllSharesCharts, redrawAllSharesCharts: redrawAllSharesCharts,
refreshHistoryChart: refreshHistoryChart, refreshHistoryChart: refreshHistoryChart,
@ -232,7 +259,8 @@
showModalDialog_AddInstrument: showModalDialog_AddInstrument, showModalDialog_AddInstrument: showModalDialog_AddInstrument,
showModalDialog_AddHolding: showModalDialog_AddHolding, showModalDialog_AddHolding: showModalDialog_AddHolding,
showModalDialog_FullScreenChart: showModalDialog_FullScreenChart, showModalDialog_FullScreenChart: showModalDialog_FullScreenChart,
showModalDialog_SoldHolding: showModalDialog_SoldHolding showModalDialog_SoldHolding: showModalDialog_SoldHolding,
updateLedgerTable: updateLedgerTable
} }
function initPage() { function initPage() {
@ -258,7 +286,13 @@
$("#groupBySymbol").prop('checked', (c == 'true') ? true : false); $("#groupBySymbol").prop('checked', (c == 'true') ? true : false);
c = Cookies.get('hideEmptyAccounts'); c = Cookies.get('hideEmptyAccounts');
$("#hideEmptyAccounts").prop('checked', (c == 'true') ? true : false); $("#hideEmptyAccounts").prop('checked', (c == 'true') ? true : false)
c = Cookies.get('showSubtotals');
$("#showSubtotals").prop('checked', (c == 'true') ? true : false);
c = Cookies.get('showCryptoHoldings');
$("#showCryptoHoldings").prop('checked', (c == 'true') ? true : false);
getInstruments(); getInstruments();
} }

View File

@ -105,19 +105,29 @@ Public Class SharePrices
'Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SubmitDailyData(" + Symbol + ") completed. Duration = " + DateDiff(DateInterval.Second, startDT, endDT).ToString()) 'Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SubmitDailyData(" + Symbol + ") completed. Duration = " + DateDiff(DateInterval.Second, startDT, endDT).ToString())
End Sub End Sub
<WebMethod()> <WebMethod()>
Public Shared Sub SubmitIntradayData(Symbol As String, DailyPrices As List(Of DataAccessLayer.PriceData), GMTOffset As Integer, Currency As String, CurrentPrice As Double, InstrumentType As String, TradeDayStart As Long, TradeDayEnd As Long) Public Shared Sub SubmitIntradayData(Symbol As String, DailyPrices As List(Of DataAccessLayer.PriceData), GMTOffset As Integer, Currency As String, CurrentPrice As Double, InstrumentType As String, TradeDayStart As Long, TradeDayEnd As Long)
'Public Shared Sub SubmitIntradayData(Symbol As String, DailyPrices As List(Of DataAccessLayer.PriceData)) 'Public Shared Sub SubmitIntradayData(Symbol As String, DailyPrices As List(Of DataAccessLayer.PriceData))
Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SubmitIntradayData webmethod: " + Symbol) Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SubmitIntradayData webmethod: " + Symbol)
DataAccessLayer.UpdateInstrument(Symbol, GMTOffset, Currency, CurrentPrice, InstrumentType, FromEpochTime(TradeDayStart), FromEpochTime(TradeDayEnd)) DataAccessLayer.UpdateInstrument(Symbol, GMTOffset, Currency, CurrentPrice, InstrumentType, FromEpochTime(TradeDayStart), FromEpochTime(TradeDayEnd))
Dim responseText As String = DataAccessLayer.InsertIntradayData(Symbol, DailyPrices) Dim responseText As String = DataAccessLayer.InsertIntradayData(Symbol, DailyPrices)
If responseText = "" Then responseText = "[]" If responseText = "" Then responseText = "[]"
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText) SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText)
End Sub End Sub
<WebMethod()> <WebMethod()>
Public Shared Sub UpdateInstrument(Symbol As String, GMTOffset As Integer, Currency As String, CurrentPrice As Double, InstrumentType As String, TradeDayStart As Long, TradeDayEnd As Long)
Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.UpdateInstrument webmethod: " + Symbol)
DataAccessLayer.UpdateInstrument(Symbol, GMTOffset, Currency, CurrentPrice, InstrumentType, FromEpochTime(TradeDayStart), FromEpochTime(TradeDayEnd))
Dim responseText As String = "{ ""Result"": ""Success"" }"
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText)
End Sub
<WebMethod()>
Public Shared Sub SwapInstrumentDisplayOrders(Symbol1 As String, Symbol2 As String) Public Shared Sub SwapInstrumentDisplayOrders(Symbol1 As String, Symbol2 As String)
Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SwapInstrumentDisplayOrders webmethod: " + Symbol1 + ", " + Symbol2) Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SwapInstrumentDisplayOrders webmethod: " + Symbol1 + ", " + Symbol2)
@ -152,7 +162,8 @@ Public Class SharePrices
'webClient.Proxy = New System.Net.WebProxy("127.0.0.1", 8888) 'webClient.Proxy = New System.Net.WebProxy("127.0.0.1", 8888)
'Set headers required by Yahoo Finance 'Set headers required by Yahoo Finance
webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0") 'webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0")
webClient.Headers.Add("User-Agent", "MMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36")
webClient.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") webClient.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
webClient.Headers.Add("Accept-Language", "en-GB,en;q=0.5") webClient.Headers.Add("Accept-Language", "en-GB,en;q=0.5")
'webClient.Headers.Add("Accept-Encoding", "gzip, deflate, br") 'webClient.Headers.Add("Accept-Encoding", "gzip, deflate, br")
@ -163,6 +174,10 @@ Public Class SharePrices
webClient.Headers.Add("Sec-Fetch-Site", "none()") webClient.Headers.Add("Sec-Fetch-Site", "none()")
webClient.Headers.Add("Sec-Fetch-User", "?1") webClient.Headers.Add("Sec-Fetch-User", "?1")
webClient.Headers.Add("sec-ch-ua", "Google Chrome"";v=""135"", ""Not-A.Brand"";v=""8"", ""Chromium"";v=""135""")
webClient.Headers.Add("sec-ch-ua-mobile", "70")
webClient.Headers.Add("sec-ch-ua-platform", "Windows")
DownloadYahooFinanceWebString = webClient.DownloadString(queryString) DownloadYahooFinanceWebString = webClient.DownloadString(queryString)
End Function End Function
<WebMethod()> <WebMethod()>
@ -355,21 +370,22 @@ Public Class SharePrices
Public Shared Sub SearchYahooFinanceShares(SearchString As String) Public Shared Sub SearchYahooFinanceShares(SearchString As String)
Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SearchYahooFinanceShares webmethod: " + SearchString) Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.SearchYahooFinanceShares webmethod: " + SearchString)
Dim webClient As New System.Net.WebClient 'Dim webClient As New System.Net.WebClient
webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0") 'webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0")
webClient.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8") 'webClient.Headers.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
webClient.Headers.Add("Accept-Language", "en-GB,en;q=0.5") 'webClient.Headers.Add("Accept-Language", "en-GB,en;q=0.5")
'webClient.Headers.Add("Accept-Encoding", "gzip, deflate, br") ''webClient.Headers.Add("Accept-Encoding", "gzip, deflate, br")
'Connection: keep -alive ''Connection: keep -alive
webClient.Headers.Add("Upgrade-Insecure-Requests", "1") 'webClient.Headers.Add("Upgrade-Insecure-Requests", "1")
webClient.Headers.Add("Sec-Fetch-Dest", "document()") 'webClient.Headers.Add("Sec-Fetch-Dest", "document()")
webClient.Headers.Add("Sec-Fetch-Mode", "navigate()") 'webClient.Headers.Add("Sec-Fetch-Mode", "navigate()")
webClient.Headers.Add("Sec-Fetch-Site", "none()") 'webClient.Headers.Add("Sec-Fetch-Site", "none()")
webClient.Headers.Add("Sec-Fetch-User", "?1") 'webClient.Headers.Add("Sec-Fetch-User", "?1")
Dim responseText As String = webClient.DownloadString("https://query1.finance.yahoo.com/v1/finance/search?q=" + SearchString + "&quotesCount=6&newsCount=0&enableFuzzyQuery=false&quotesQueryId=tss_match_phrase_query&multiQuoteQueryId=multi_quote_single_token_query&newsQueryId=news_ss_symbols&enableCb=false&enableNavLinks=false&vespaNewsTimeoutMs=600") 'Dim responseText As String = webClient.DownloadString("https://query1.finance.yahoo.com/v1/finance/search?q=" + SearchString + "&quotesCount=6&newsCount=0&enableFuzzyQuery=false&quotesQueryId=tss_match_phrase_query&multiQuoteQueryId=multi_quote_single_token_query&newsQueryId=news_ss_symbols&enableCb=false&enableNavLinks=false&vespaNewsTimeoutMs=600")
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText) Dim responseText As String = DownloadYahooFinanceWebString("https://query1.finance.yahoo.com/v1/finance/search?q=" + SearchString + "&quotesCount=6&newsCount=0&enableFuzzyQuery=false&quotesQueryId=tss_match_phrase_query&multiQuoteQueryId=multi_quote_single_token_query&newsQueryId=news_ss_symbols&enableCb=false&enableNavLinks=false&vespaNewsTimeoutMs=600")
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText)
End Sub End Sub
<WebMethod()> <WebMethod()>
@ -390,11 +406,36 @@ Public Class SharePrices
<WebMethod()>
Public Shared Sub GetAggregatedCurrentHoldings()
'Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.GetAggregatedCurrentHoldings webmethod")
Dim responseText As String = DataAccessLayer.GetAggregatedCurrentHoldings()
If responseText = "" Then responseText = "[]"
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText)
End Sub
<WebMethod()>
Public Shared Sub GetCurrentHoldings()
'Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.GetCurrentHoldings webmethod")
Dim responseText As String = DataAccessLayer.GetCurrentHoldings()
If responseText = "" Then responseText = "[]"
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText)
End Sub
<WebMethod()>
Public Shared Sub GetTradeHistory()
'Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.GetTradeHistory webmethod")
Dim responseText As String = DataAccessLayer.GetTradeHistory()
If responseText = "" Then responseText = "[]"
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText)
End Sub
<WebMethod()>
<WebMethod()>
Public Shared Sub TestWebMethod(Symbol As String, DailyPrices As List(Of DataAccessLayer.PriceData)) Public Shared Sub TestWebMethod(Symbol As String, DailyPrices As List(Of DataAccessLayer.PriceData))
Dim startDT As Date = Now() Dim startDT As Date = Now()
Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.TestWebMethod: " + Symbol) Debug.Print(Now().ToString("yyyy-MM-dd HH:mm:ss") + " - SharePrices.TestWebMethod: " + Symbol)

View File

@ -260,8 +260,10 @@
<Content Include="scripts\jquery\jquery.marquee.min.js" /> <Content Include="scripts\jquery\jquery.marquee.min.js" />
<Content Include="scripts\js.cookie-2.2.1.min.js" /> <Content Include="scripts\js.cookie-2.2.1.min.js" />
<Content Include="scripts\SharePrices.js" /> <Content Include="scripts\SharePrices.js" />
<Content Include="scripts\SharePrices_Accounts.js" />
<Content Include="scripts\SharePrices_Charts.js" /> <Content Include="scripts\SharePrices_Charts.js" />
<Content Include="scripts\SharePrices_Holdings.js" /> <Content Include="scripts\SharePrices_Holdings.js" />
<Content Include="scripts\SharePrices_Ledger.js" />
<Content Include="scripts\tablesorter\dragtable.mod.css" /> <Content Include="scripts\tablesorter\dragtable.mod.css" />
<Content Include="scripts\tablesorter\filter.formatter.css" /> <Content Include="scripts\tablesorter\filter.formatter.css" />
<Content Include="scripts\tablesorter\highlights.css" /> <Content Include="scripts\tablesorter\highlights.css" />

View File

@ -39,6 +39,11 @@ td {vertical-align: top;}
#spnCurrencies a { color: white; } #spnCurrencies a { color: white; }
#spnCurrencies a:visited { color: white; } #spnCurrencies a:visited { color: white; }
.open a:link { color: white; }
.open a:visited { color: white; }
.closed a:link { color: #757575; }
.closed a:visited { color: #757575; }
a:link { color: #f473ff; } a:link { color: #f473ff; }
a:visited { color: #9a34b7; } a:visited { color: #9a34b7; }
@ -47,20 +52,49 @@ a:visited { color: #9a34b7; }
.miniHoldings th { font-size: x-small; border: 1px solid #505050; } .miniHoldings th { font-size: x-small; border: 1px solid #505050; }
.soldHolding { text-decoration: line-through; } .soldHolding { text-decoration: line-through; }
/*tr.highlighted, td.highlighted { background-color: gold; }*/
.highlighted { background-color: gold; }
.mainHoldings { font-size: small; } .mainHoldings { font-size: small; }
table.mainHoldings { width: 100%; } table.mainHoldings { width: 100%; }
table.mainHoldings th { background-color: #101040; }
table.mainHoldings th, table.mainHoldings td { padding-left: 5px; padding-right: 5px; } table.mainHoldings th, table.mainHoldings td { padding-left: 5px; padding-right: 5px; }
table.mainHoldings tr:hover { background-color: #404090; } table.mainHoldings tr:hover { background-color: #404090; }
.mainHoldingsSpacer { font-size: 2pt; }
.holdingsSubtotal td { font-weight: bold; padding-top: 6px; padding-bottom: 12px; }
/*.holdingsSubtotal td { font-weight: bold; }*/
.holdingsSubtotal { font-weight: bold; }
/*.holdingsGrandTotal td { font-weight: bold; padding-top: 10px; padding-bottom: 12px; }*/
/*.holdingsGrandTotal td { font-weight: bold; }*/
.holdingsGrandTotal { font-weight: bold; }
.holdingsRow { background-color: #10101a }
.watchlist { font-size: small; } /*tr.highlighted, td.highlighted { background-color: gold; }*/
.highlighted { background-color: gold; }
.highlightedProfit { color:black; background-color: #07b200; }
.highlightedLoss { color:white; background-color: #ff4141; }
.tablesorter .filtered { display: none; }
.ledger { font-size: x-small; }
table.ledger { width: 100%; }
table.ledger th { background-color: #101040; }
table.ledger th, table.ledger td { padding-left: 5px; padding-right: 5px; }
table.ledger tr:hover { background-color: #404090; }
.ledgerRow.odd { background-color: #28293b; }
/*.ledgerRow.even { background-color: #090b25 }*/
/*
.newHoldingsTable { font-size: small; }
table.newHoldingsTable { width: 100%; }
table.newHoldingsTable th, table.newHoldingsTable td { padding-left: 5px; padding-right: 5px; }
table.newHoldingsTable tr:hover { background-color: #404090; }
*/
.watchlist {
font-size: small;
}
/*table.watchlist { width: 100%; }*/ /*table.watchlist { width: 100%; }*/
table.watchlist th, table.watchlist td { padding-left: 5px; padding-right: 5px; } table.watchlist th, table.watchlist td { padding-left: 5px; padding-right: 5px; }
table.watchlist tr:hover { background-color: #404090; } table.watchlist tr:hover { background-color: #404090; }
.accounts { font-size: small; } .accounts { font-size: 9pt; }
/*table.accounts { width: 100%; }*/ /*table.accounts { width: 100%; }*/
table.accounts th, table.accounts td { padding-left: 5px; padding-right: 5px; } table.accounts th, table.accounts td { padding-left: 5px; padding-right: 5px; }
table.accounts tr:hover { background-color: #404090; } table.accounts tr:hover { background-color: #404090; }
@ -137,8 +171,6 @@ td.no-border { border: 0px; text-align: right; }
border-radius: 4px; border-radius: 4px;
} }
.deletebutton { color: red; cursor: pointer; } .deletebutton { color: red; cursor: pointer; }
span.addHolding { cursor: pointer; } span.addHolding { cursor: pointer; }
@ -147,142 +179,3 @@ span.addHolding { cursor: pointer; }
.marquee { width: 600px; overflow: hidden; font-size: small; /*border: 1px solid #ccc;*/ /*background: #ccc;*/ } .marquee { width: 600px; overflow: hidden; font-size: small; /*border: 1px solid #ccc;*/ /*background: #ccc;*/ }
.marquee div { padding: 1px 0px 1px 0px; } .marquee div { padding: 1px 0px 1px 0px; }
/*
.highcharts-hollowcandlestick-series .highcharts-point-down {
fill: #ff4141;
stroke: #ff4141;
}*/
/*.highcharts-hollowcandlestick-series .highcharts-point-down-bearish-up {
fill: #35bd00;
stroke: #35bd00;
}*/
/*
.highcharts-hollowcandlestick-series .highcharts-point-up {
fill: #07b200;
stroke: #07b200;
}*/
/*
html, body { min-height: 100% !important; height: 100%; width: 100%; }
body { font-family: Verdana, Arial, Helvetica, sans-serif; margin-left: 0px; background-color: black; color: #B0B0B0; }
/ * The navigation bar * /
.navbar { overflow: hidden; background-color: #333; position: fixed; top: 0; width: 100%; z-index: 100; }
.navbar a { float: left; display: block; color: #f2f2f2; text-align: center; padding: 7px 16px; text-decoration: none; }
.navbar label { color: #f2f2f2; }
.navbar a:hover { background: #ddd; color: white; }
.activenav { float: left; display: block; color: #f2f2f2 !important; background-color: #307D30 !important; text-align: center; padding: 7px 16px; text-decoration: none; }
.main { height: 100%; width: 100%; margin-top: 34px; / * Add a top margin to avoid content overlay * / }
/ * #chartDiv { height: 100%; overflow: scroll; } * /
#chartDiv { margin-top: 34px; }
#holdingsDiv { margin-top: 34px; }
#accoountsDiv { margin-top: 34px; }
#analDiv { margin-top: 34px; }
div.activetab {position: absolute; top: 0; height: 100%; width: 100%; z-index: 2; background-color: black; overflow: scroll; / *display: inline;* /}
div.inactivetab {position: absolute; top: 0; height:100%; width: 100%; z-index: 0; overflow: scroll; / *display: none;* /}
td {vertical-align: top;}
.shareRow { / *background-color: #ffffff;* / }
.altShareRow { background-color: #212121; / *#2a2a2a;* / }
.instrumentName { color: white; }
#spnTotalHoldings { color: white; padding-left: 50px; }
a:link { color: #f473ff; }
a:visited { color: #9a34b7; }
.miniHoldings { border-collapse: collapse; border-spacing: 0; }
.miniHoldings td { font-size: x-small; border: 1px solid #505050; }
.miniHoldings th { font-size: x-small; border: 1px solid #505050; }
.soldHolding { text-decoration: line-through; }
tr.highlighted, td.highlighted { background-color: gold; }
.mainHoldings { font-size: small; }
table.mainHoldings { width: 100%; }
table.mainHoldings th, table.mainHoldings td { padding-left: 5px; padding-right: 5px; }
table.mainHoldings tr:hover { background-color: #404090; }
.accounts { font-size: small; }
/ *table.accounts { width: 100%; }* /
table.accounts th, table.accounts td { padding-left: 5px; padding-right: 5px; }
table.accounts tr:hover { background-color: #404090; }
.analysis { font-size: small; }
table.analysis { width: 100%; }
table.analysis th, table.analysis td { padding-left: 5px; padding-right: 5px; }
table.analysis tbody tr { white-space: nowrap; }
table.analysis tr:hover { background-color: #404090; }
.pcLabel { position: relative; background-color: transparent; text-align: center; z-index: 2; }
.pcBackground { position: absolute; z-index: 1; }
.price-summary { font-size: x-small; }
.current-value { font-size: medium; }
.num {text-align: right;}
.summary { width: 100%; border-collapse: collapse; }
.spacer { padding-top: 6px; }
.profit { color: #07b200; / * limegreen * /}
.loss { color: #ee2727; / *red;* / / * firebrick * /}
td.no-border { border: 0px; text-align: right; }
.flot-tick-label { color: #b0b0b0 }
.LongSummary { font-size: x-small; }
.LongChart { height: 150px; width: 300px; }
.MidSummary { font-size: x-small; }
.MidChart { height: 150px; width: 300px; }
.ShortSummary { font-size: x-small; }
.ShortChart { height: 150px; width: 300px; }
.DaySummary { font-size: x-small; }
.DayChart { height: 136px; width: 300px; }
.FullScreenChart { height: 300px; width: 400px; }
.HoldingCurrenciesChart { height: 250px; width: 250px; }
/ *#divHoldingCurrenciesChart .pieLabel { color: red !important; background-color: black; }* /
#divHoldingCurrenciesChart div.pieLabel { font-size: x-small; text-align: center; padding: 2px; color: white; background-color: black }
#divHoldingCurrenciesChartCurrentValue div.pieLabel { font-size: x-small; text-align: center; padding: 2px; color: white; background-color: black }
#divAccountBookCost div.pieLabel { font-size: x-small; text-align: center; padding: 2px; color: white; background-color: black }
#divAccountValue div.pieLabel { font-size: x-small; text-align: center; padding: 2px; color: white; background-color: black }
.flotTip
{
padding: 3px 5px;
background-color: #000;
z-index: 101;
color: #fff;
box-shadow: 0 0 10px #555;
opacity: .7;
filter: alpha(opacity=70);
border: 2px solid #fff;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.deletebutton { color: red; cursor: pointer; }
span.addHolding { cursor: pointer; }
.flot-text { font-size: x-small !important; }
.chart-tooltip { position: absolute; border: 1px solid #fdd; padding: 2px; background-color: #fee; opacity: 0.80; display: none; z-index: 6; }
#selectInstrument2 { width: 100%; }
*/

View File

@ -1,12 +1,12 @@
// @ts-check // @ts-check
//Testing gitea.copeland-bowen.com #3
import {formatAmount, generateAxisBreaks, getProfitOrLoss, timespans} from "./SharePrices_Common.js"; import {formatAmount, generateAxisBreaks, getProfitOrLoss, timespans} from "./SharePrices_Common.js";
import {createLongChart, createMidChart, createShortChart, createSingleDayChart, createChart_Flot, import {createLongChart, createMidChart, createShortChart, createSingleDayChart, createChart_Flot,
createChart, createFullScreenChart, createFullScreenChart_Flot, createFullScreenComparisonChart, createChart, createFullScreenChart, createFullScreenChart_Flot, createFullScreenComparisonChart,
createFullScreenComparisonChart_Flot createFullScreenComparisonChart_Flot
} from "./SharePrices_Charts.js"; } from "./SharePrices_Charts.js";
import {createHoldingsTable} from "./SharePrices_Holdings.js"; import { updateHoldingsTables } from "./SharePrices_Holdings.js";
import { createAccountsTables } from "./SharePrices_Accounts.js";
'use strict'; 'use strict';
@ -26,14 +26,43 @@ var vars = {
previousDay: 0, previousDay: 0,
previousClose: 0, previousClose: 0,
previousWeek: 0, previousWeek: 0,
previousWeekClose:0 previousWeekClose: 0,
currentHoldings: {},
currentAggHoldingsRows: {
Data: [],
rowID: function (r) {
return (r.Symbol).replaceAll(' ', '_').replaceAll('=', '_');
},
indexOfRowID: function (rowID) {
return this.Data.map(function (item) {
return vars.currentAggHoldingsRows.rowID(item.attributes)
}).indexOf(rowID)
},
GetRow: function (r) {
return this.Data[this.indexOfRowID(this.rowID(r))]
}
},
currentHoldingsRows: {
Data: [],
rowID: function (r) {
return (r.TaxBucket + '_' + r.AccountName + '_' + r.Symbol).replaceAll(' ', '_').replaceAll('=', '_');
},
indexOfRowID: function (rowID) {
return this.Data.map(function (item) {
return vars.currentHoldingsRows.rowID(item.attributes)
}).indexOf(rowID)
},
GetRow: function (r) {
return this.Data[this.indexOfRowID(this.rowID(r))]
}
}
} }
//var timespans = { oneSecond: 1000, oneMinute: 60 * 1000, oneHour: 60 * 60 * 1000, oneDay: 24 * 60 * 60 * 1000, oneWeek: 7 * 24 * 60 * 60 * 1000, oneMonth: 31 * 24 * 60 * 60 * 1000 }; //var timespans = { oneSecond: 1000, oneMinute: 60 * 1000, oneHour: 60 * 60 * 1000, oneDay: 24 * 60 * 60 * 1000, oneWeek: 7 * 24 * 60 * 60 * 1000, oneMonth: 31 * 24 * 60 * 60 * 1000 };
//var lastSuccessfulFetch; //var lastSuccessfulFetch;
var currencyFormatter = new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' }); var currencyFormatter = new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' });
var instrumentSearchResults = []; var instrumentSearchResults = [];
var tablesUpdateTimings = { lastUpdate: 0, timeBetweenUpdates: 10000, timer: 0, updateNeeded: true }; var tablesUpdateTimings = { lastUpdate: 0, timeBetweenUpdates: 15000, timer: 0, updateNeeded: true };
var indexMarquee = { var indexMarquee = {
newContent: '', newContent: '',
currentContent: '', currentContent: '',
@ -127,7 +156,7 @@ var Instruments = {
let lastFetchedDate = this.Data[0].lastFetchedIntraday; let lastFetchedDate = this.Data[0].lastFetchedIntraday;
let lastFetchedIndex = 0; let lastFetchedIndex = 0;
for (let i = 1; i < this.Data.length; i++) { for (let i = 1; i < this.Data.length; i++) {
if (this.Data[i].Symbol != 'GBP' && this.Data[i].Symbol != 'GBp') { if (this.Data[i].Symbol != 'GBP' && this.Data[i].Symbol != 'GBp' && this.Data[i].TrackPriceHistory == 1) {
//if (!this.Data[i].lastFetchedIntraday) { this.Data[i].lastFetchedIntraday = this.Data[i].MaxIntradayDate }; //if (!this.Data[i].lastFetchedIntraday) { this.Data[i].lastFetchedIntraday = this.Data[i].MaxIntradayDate };
if (!this.Data[i].lastFetchedIntraday) { this.Data[i].lastFetchedIntraday = new Date().getTime() - vars.fetchTiming.fetchIntervalIntraday + (2 * timespans.oneMinute) }; if (!this.Data[i].lastFetchedIntraday) { this.Data[i].lastFetchedIntraday = new Date().getTime() - vars.fetchTiming.fetchIntervalIntraday + (2 * timespans.oneMinute) };
if (lastFetchedDate > this.Data[i].lastFetchedIntraday) { if (lastFetchedDate > this.Data[i].lastFetchedIntraday) {
@ -247,6 +276,14 @@ Date.prototype.yyyymmddhhmmss = function () {
var ss = this.getSeconds().toString(); var ss = this.getSeconds().toString();
return yyyy + '-' + (mm[1] ? mm : "0" + mm[0]) + '-' + (dd[1] ? dd : "0" + dd[0]) + " " + (hh[1] ? hh : "0" + hh[0]) + ":" + (nn[1] ? nn : "0" + nn[0]) + ":" + (ss[1] ? ss : "0" + ss[0]); return yyyy + '-' + (mm[1] ? mm : "0" + mm[0]) + '-' + (dd[1] ? dd : "0" + dd[0]) + " " + (hh[1] ? hh : "0" + hh[0]) + ":" + (nn[1] ? nn : "0" + nn[0]) + ":" + (ss[1] ? ss : "0" + ss[0]);
}; };
Date.prototype.yyyymmddhhmm = function () {
var yyyy = this.getFullYear().toString();
var mm = (this.getMonth() + 1).toString(); // getMonth() is zero-based
var dd = this.getDate().toString();
var hh = this.getHours().toString();
var nn = this.getMinutes().toString();
return yyyy + '-' + (mm[1] ? mm : "0" + mm[0]) + '-' + (dd[1] ? dd : "0" + dd[0]) + " " + (hh[1] ? hh : "0" + hh[0]) + ":" + (nn[1] ? nn : "0" + nn[0]);
};
Date.prototype.yyyymmdd = function () { Date.prototype.yyyymmdd = function () {
var yyyy = this.getFullYear().toString(); var yyyy = this.getFullYear().toString();
var mm = (this.getMonth() + 1).toString(); // getMonth() is zero-based var mm = (this.getMonth() + 1).toString(); // getMonth() is zero-based
@ -289,7 +326,11 @@ Number.prototype.autoScale = function () {
return this.toFixed(1); return this.toFixed(1);
} else { } else {
if (a < 0.001) { if (a < 0.001) {
return this.toExponential(2); if (a == 0) {
return '0';
} else {
return this.toExponential(2);
}
} else { } else {
return this.toFixed(2); return this.toFixed(2);
} }
@ -383,7 +424,7 @@ export function createSharesTable() {
logError({ MSG: "Error in createSharesTable", err: err }); logError({ MSG: "Error in createSharesTable", err: err });
} }
}; };
export function createSharesTableRow(instrument) { function createSharesTableRow(instrument) {
function getHoldingsTable(Instrument) { function getHoldingsTable(Instrument) {
if (Instrument.Holdings.length > 0) { if (Instrument.Holdings.length > 0) {
let totalUnits = 0; let totalUnits = 0;
@ -769,7 +810,7 @@ function getYahooDailyData(Instrument) {
createLongChart(Instrument); createLongChart(Instrument);
} else { } else {
//console.info("No data received for symbol: " + Instrument.Symbol); //console.info("No data received for symbol: " + Instrument.Symbol);
logWarning({ MSG: "No data received for symbol: " + Instrument.Symbol, response: response }) logWarning({ MSG: "getYahooDailyData - No data received for symbol: " + Instrument.Symbol, response: response })
} }
}, },
failure: function (response) { failure: function (response) {
@ -829,14 +870,14 @@ function getYahooIntradayData(Instrument) {
createMidChart(Instrument); createMidChart(Instrument);
createShortChart(Instrument); createShortChart(Instrument);
} else { } else {
console.info("No NEW data received for symbol: " + Instrument.Symbol); console.info("getYahooIntradayData - No NEW data received for symbol: " + Instrument.Symbol);
} }
} else { } else {
//logWarning({ MSG: "No timestamp series received for symbol: " + Instrument.Symbol, response: response }); //logWarning({ MSG: "No timestamp series received for symbol: " + Instrument.Symbol, response: response });
} }
} else { } else {
//console.warn("No data received for symbol: " + Instrument.Symbol); //console.warn("No data received for symbol: " + Instrument.Symbol);
logWarning({ MSG: "No data received for symbol: " + Instrument.Symbol, response: response }); logWarning({ MSG: "getYahooIntradayData - No data received for symbol: " + Instrument.Symbol, response: response });
} }
}, },
failure: function (response) { failure: function (response) {
@ -859,10 +900,15 @@ function getYahooSingleDayData(Instrument) {
success: function (response) { success: function (response) {
vars.fetchTiming.lastFetchDuration = (new Date().getTime()) - vars.fetchTiming.lastFetchStartTime; vars.fetchTiming.lastFetchDuration = (new Date().getTime()) - vars.fetchTiming.lastFetchStartTime;
let newData = []; let newData = [];
let dbUpdateNeeded = false;
if (response.chart && response.chart.result) { if (response.chart && response.chart.result) {
let dataSeries = response.chart.result[0]; let dataSeries = response.chart.result[0];
if (dataSeries.meta) { if (dataSeries.meta) {
if (Instrument.CurrentPrice != dataSeries.meta.regularMarketPrice) {
dbUpdateNeeded = true;
}
Instrument.SingleDayPreviousClose = dataSeries.meta.previousClose; Instrument.SingleDayPreviousClose = dataSeries.meta.previousClose;
Instrument.SingleDayStartDate = dataSeries.meta.currentTradingPeriod.regular.start * 1000; Instrument.SingleDayStartDate = dataSeries.meta.currentTradingPeriod.regular.start * 1000;
Instrument.SingleDayEndDate = dataSeries.meta.currentTradingPeriod.regular.end * 1000; Instrument.SingleDayEndDate = dataSeries.meta.currentTradingPeriod.regular.end * 1000;
@ -908,12 +954,26 @@ function getYahooSingleDayData(Instrument) {
} else { } else {
//console.warn("No timestamp series received for symbol: " + Instrument.Symbol); //console.warn("No timestamp series received for symbol: " + Instrument.Symbol);
//logWarning("No timestamp series received for symbol: " + Instrument.Symbol); //logWarning("No timestamp series received for symbol: " + Instrument.Symbol);
logWarning({ MSG: "No timestamp series received for symbol: " + Instrument.Symbol, response: response }); logWarning({ MSG: "getYahooSingleDayData - No timestamp series received for symbol: " + Instrument.Symbol, response: response });
}
if (dbUpdateNeeded) {
$.ajax({
type: "POST",
contentType: "application/json",
url: "SharePrices.aspx/UpdateInstrument?S=" + Instrument.Symbol,
dataType: "json",
data: JSON.stringify({ Symbol: Instrument.Symbol, GMTOffset: Instrument.GMTOffset, Currency: Instrument.Currency, CurrentPrice: Instrument.CurrentPrice, InstrumentType: Instrument.InstrumentType, TradeDayStart: Instrument.SingleDayStartDate, TradeDayEnd: Instrument.SingleDayEndDate }),
success: function (response) {
//console.info('UpdateInstrument success: ' + Instrument.Symbol + ' - ' + JSON.stringify(response));
},
failure: function (response) { console.error("getYahooSingleDayData - UpdateInstrument error: " + JSON.stringify(response)); }
});
} }
} else { } else {
//console.info("No data received for symbol: " + Instrument.Symbol); //console.info("No data received for symbol: " + Instrument.Symbol);
//logInfo("No data received for symbol: " + Instrument.Symbol); //logInfo("No data received for symbol: " + Instrument.Symbol);
logWarning({ MSG: "No data received for symbol: " + Instrument.Symbol, response: response }); logWarning({ MSG: "getYahooSingleDayData - No data received for symbol: " + Instrument.Symbol, response: response });
} }
}, },
failure: function (response) { failure: function (response) {
@ -1014,6 +1074,34 @@ function submitNewDailyData(Instrument, NewData) {
} }
function submitNewIntradayData(Instrument, NewData) { function submitNewIntradayData(Instrument, NewData) {
//console.info("submitNewIntradayData"); //console.info("submitNewIntradayData");
//Submit the data in small chunks to avoid the HTTP payload getting too big
let noSubmitted = 0;
while (noSubmitted < NewData.length) {
let thisSubmission = [];
for (let x = noSubmitted; x < NewData.length && thisSubmission.length < 300; x++) {
thisSubmission.push(NewData[x]);
}
noSubmitted += thisSubmission.length;
//if (noSubmitted < NewData.length) {
// console.info("Need another round");
//}
$.ajax({
type: "POST",
contentType: "application/json",
url: "SharePrices.aspx/SubmitIntradayData?S=" + Instrument.Symbol,
dataType: "json",
data: JSON.stringify({ Symbol: Instrument.Symbol, DailyPrices: thisSubmission, GMTOffset: Instrument.GMTOffset, Currency: Instrument.Currency, CurrentPrice: Instrument.CurrentPrice, InstrumentType: Instrument.InstrumentType, TradeDayStart: Instrument.SingleDayStartDate, TradeDayEnd: Instrument.SingleDayEndDate }),
success: function (response) {
//console.info('SubmitIntradayData success: ' + Instrument.Symbol + ' - ' + JSON.stringify(response));
},
failure: function (response) { console.error("SubmitIntradayData error: " + JSON.stringify(response)); }
});
}
/*
$.ajax({ $.ajax({
type: "POST", type: "POST",
contentType: "application/json", contentType: "application/json",
@ -1026,6 +1114,7 @@ function submitNewIntradayData(Instrument, NewData) {
}, },
failure: function (response) { console.error("SubmitIntradayData error: " + JSON.stringify(response)); } failure: function (response) { console.error("SubmitIntradayData error: " + JSON.stringify(response)); }
}); });
*/
//Add new data to Instrument //Add new data to Instrument
let currentSummary = {}; let currentSummary = {};
@ -1050,207 +1139,20 @@ function submitNewIntradayData(Instrument, NewData) {
} }
function updateTables() { function updateTables() {
//Only update the tables every 5 seconds (unless lastTablesUpdate has been reset) //Only update the tables every x seconds
if (tablesUpdateTimings.updateNeeded && tablesUpdateTimings.lastUpdate + tablesUpdateTimings.timeBetweenUpdates < new Date().getTime()) { if (tablesUpdateTimings.updateNeeded && tablesUpdateTimings.lastUpdate + tablesUpdateTimings.timeBetweenUpdates < new Date().getTime()) {
tablesUpdateTimings.lastUpdate = new Date().getTime(); tablesUpdateTimings.lastUpdate = new Date().getTime();
createHoldingsTable(Instruments, vars); //createHoldingsTable(Instruments, vars);
createAccountsTables(); createAccountsTables(Instruments);
createAnalysisTable(); createAnalysisTable();
createIndexMarquee(); createIndexMarquee();
updateCurrenciesSpan(); updateCurrenciesSpan();
updateHoldingsTables(Instruments, vars);
} }
} }
function createAccountsTables() {
function getAccounts() {
let accounts = [];
function indexOfAccount(accountName) { return accounts.map(function (item) { return item.accountName; }).indexOf(accountName); };
function getAccount(accountName) { return accounts[indexOfAccount(accountName)]; };
function addAccountHolding(instrument, exchangeRate, holding) {
let a = getAccount(holding.AccountName);
if (!a) {
a = { accountName: holding.AccountName, holdings: [], totalCostGBP: 0, totalValueGBP: 0, totalGainGBP: 0, totalCashGBP: 0 };
accounts.push(a);
}
let h = {
instrumentName: instrument.InstrumentName,
symbol: instrument.Symbol,
instrumentType: instrument.InstrumentType,
currency: instrument.Currency,
purchaseDate: holding.PurchaseDate,
purchasePricePerUnit: holding.PurchasePricePerUnit,
noUnits: holding.NoUnits,
cost: holding.NoUnits * holding.PurchasePricePerUnit
}
//if (exchangeRate) {
//h.costGBP = h.cost / exchangeRate;
h.costGBP = holding.BookCostGBP;
if (instrument.InstrumentType != 'CURRENCY') {
a.totalCostGBP += holding.BookCostGBP;
}
//}
if (instrument.CurrentPrice) {
h.currentPrice = instrument.CurrentPrice;
h.currentValue = holding.NoUnits * instrument.CurrentPrice;
h.gain = h.currentValue - h.cost;
if (exchangeRate) {
h.currentValueGBP = h.currentValue / exchangeRate;
//h.gainGBP = h.gain / exchangeRate;
h.gainGBP = h.currentValueGBP - h.costGBP;
if (instrument.InstrumentType != 'CURRENCY') {
a.totalGainGBP += h.gainGBP;
a.totalValueGBP += h.currentValueGBP;
}
}
}
if (instrument.InstrumentType == 'CURRENCY') {
//Don't add cash holdings - just add the cash value to the account
a.totalCashGBP += h.currentValueGBP;
} else {
a.holdings.push(h);
}
}
for (let ix = 0; ix < Instruments.Data.length; ix++) {
let i = Instruments.Data[ix];
let exchangegRate = Instruments.GetExchangeRate(i.Currency, 'GBP');
for (let hx = 0; hx < i.Holdings.length; hx++) {
let h = i.Holdings[hx];
if (h.SoldDate == null) {
addAccountHolding(i, exchangegRate, h);
}
}
}
return accounts;
}
let accounts = getAccounts();
//Sort the accounts array by accountName
accounts.sort(function (a, b) {
if (a.accountName < b.accountName) return -1;
if (a.accountName > b.accountName) return 1;
return 0;
});
//let summaryTable = "<table class='accounts' id='accountsSummaryTable'><thead><tr><th>Account Name</th><th>No. Holdings</th><th>Total Cost (GBP)</th><th>Current Value</th><th>Total Gain</th></tr></thead><tbody>";
let summaryTable = "<table class='accounts' id='accountsSummaryTable'><thead><tr>" +
"<th>Account Name</th>" +
"<th>No. Holdings</th>" +
"<th>Total Cost (GBP)</th>" +
"<th>Total Gains (GBP)</th>" +
"<th>Total Losses (GBP)</th>" +
"<th>Current Investements Value</th>" +
"<th>NET Gain</th>" +
"<th>Cash Balance GBP</th>" +
"<th>Total Value GBP</th>" +
"</tr></thead><tbody>";
let accountsTables = ''
let tableIDs = ['accountsSummaryTable'];
let hideEmptyAccounts = $('#hideEmptyAccounts').prop('checked');
let altRow = 1;
for (let ax = 0; ax < accounts.length; ax++) {
let a = accounts[ax];
let accountGainsGBP = 0;
let accountLossesGBP = 0;
let accountValueGBP = 0;
let profitOrLoss = a.totalGainGBP < 0 ? 'loss' : 'profit';
if (a.holdings.length > 0) {
altRow = !altRow;
accountsTables += '<br>' + a.accountName + '<br>'
let tableID = 'accountTable' + ax;
tableIDs.push(tableID);
accountsTables += '<table class="accounts" id="' + tableID + '">' +
'<thead><tr>' +
'<th>Name</th>' +
'<th>Symbol</th>' +
'<th>Buy Date</th>' +
'<th>No Units</th>' +
'<th>Buy Price</th>' +
'<th>Current Price</th>' +
'<th>Book Cost</th>' +
'<th>Approx Book Cost £</th>' +
'<th>Current Value</th>' +
'<th>Current Value £</th>' +
'<th>Gain</th>' +
'<th>Gain £</th>' +
'<th>Gain %</th>' +
'</tr></thead><tbody>';
let accountAltRow = 1;
for (let hx = 0; hx < a.holdings.length; hx++) {
let h = a.holdings[hx];
accountAltRow = !accountAltRow;
let holdingProfitOrLoss = h.gain < 0 ? 'loss' : 'profit';
let holdingGBPProfitOrLoss = h.gainGBP < 0 ? 'loss' : 'profit';
if (h.gainGBP > 0) {
accountGainsGBP += h.gainGBP;
} else {
accountLossesGBP += h.gainGBP;
}
accountValueGBP += h.currentValueGBP;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td>' + h.instrumentName + '</td>' +
'<td>' + h.symbol + '</td>' +
'<td>' + new Date(h.purchaseDate).yyyymmdd() + '</td>' +
'<td class="num">' + h.noUnits + '</td>' +
'<td class="num">' + formatAmount(h.purchasePricePerUnit, h.currency, 2) + '</td>' +
'<td class="num">' + formatAmount(h.currentPrice, h.currency, 2) + '</td>' +
'<td class="num">' + (h.currency == 'GBp' ? formatAmount(h.cost / 100, 'GBP', 2) : formatAmount(h.cost, h.currency, 2)) + '</td>' +
'<td class="num">' + formatAmount(h.costGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + (h.currency == 'GBp' ? formatAmount(h.currentValue / 100, 'GBP', 2) : formatAmount(h.currentValue, h.currency, 2)) + '</td>' +
'<td class="num">' + formatAmount(h.currentValueGBP, 'GBP', 2) + '</td>' +
'<td class="num ' + holdingProfitOrLoss + '">' + formatAmount(h.gain, h.currency, 2) + '</td>' +
'<td class="num ' + holdingGBPProfitOrLoss + '">' + formatAmount(h.gainGBP, 'GBP', 2) + '</td>' +
//'<td class="num ' + holdingProfitOrLoss + '">' + ((h.gain / h.cost) * 100).toFixed(1) + '%</td>' +
'<td class="num ' + holdingGBPProfitOrLoss + '">' + ((h.gainGBP / h.costGBP) * 100).toFixed(1) + '%</td>' +
'</tr>';
}
//Add the Total Gains
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="11">Total Gains</td>' +
'<td class="num profit">' + formatAmount(accountGainsGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
//Add the Total Losses
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="11">Total Losses</td>' +
'<td class="num loss">' + formatAmount(accountLossesGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
//Add the NET Gains summary line
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="9">Account Value:</td>' +
'<td class="num ' + ((accountGainsGBP+accountLossesGBP) > 0 ? 'profit' : 'loss') + '">' + formatAmount(accountValueGBP, 'GBP', 2) + '</td>' +
'<td class="num">NET Gain</td>' +
'<td class="num ' + ((accountGainsGBP + accountLossesGBP) > 0 ? 'profit' : 'loss') + '">' + formatAmount(accountGainsGBP + accountLossesGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
accountsTables += '</tbody></table>';
}
//Add an entry to the summary table
if (a.totalValueGBP + a.totalCashGBP > 0 || !hideEmptyAccounts) {
summaryTable += "<tr" + (altRow ? ' class="altShareRow"' : '') + "><td>" + a.accountName + "</td>" +
"<td>" + a.holdings.length + "</td>" +
"<td class='num'>" + formatAmount(a.totalCostGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(accountGainsGBP, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(accountLossesGBP, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalValueGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num " + profitOrLoss + "'>" + formatAmount(a.totalGainGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalCashGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalValueGBP + a.totalCashGBP || 0, 'GBP', 2) + "</td>" +
"</tr>";
}
}
summaryTable += "</tbody></table>";
$("#accountsSummaryDiv").html(summaryTable + '<br>' + accountsTables);
}
function createAnalysisTable() { function createAnalysisTable() {
function getHighestPriceBeforeDate(Instrument, maxDT) { function getHighestPriceBeforeDate(Instrument, maxDT) {
if (Instrument.DailyData) { if (Instrument.DailyData) {
@ -1465,15 +1367,16 @@ function createIndexMarquee() {
//if (i.InstrumentType == 'INDEX' || i.InstrumentType == 'FUTURE') { //if (i.InstrumentType == 'INDEX' || i.InstrumentType == 'FUTURE') {
if (i.ShowInMarquee == 'A') { if (i.ShowInMarquee == 'A') {
let openOrClosed = Instruments.MarketIsOpen(i) == 1 ? 'open' : 'closed'; let openOrClosed = Instruments.MarketIsOpen(i) == 1 ? 'open' : 'closed';
let label = '<a class="' + openOrClosed + '" target="_blank" href="https://uk.finance.yahoo.com/quote/' + i.Symbol + '">' + i.DisplayName + '</a>';
if (i.SingleDayPreviousClose) { if (i.SingleDayPreviousClose) {
let percentChange = ((i.CurrentPrice / i.SingleDayPreviousClose) - 1) * 100; let percentChange = ((i.CurrentPrice / i.SingleDayPreviousClose) - 1) * 100;
if (percentChange < 0) { if (percentChange < 0) {
t.push('<font class="' + openOrClosed + '">' + i.DisplayName + '<br/>' + i.CurrentPrice + ' </font><font class="loss">' + percentChange.toFixed(1) + '%</font>'); t.push('<font class="' + openOrClosed + '">' + label + '<br/>' + i.CurrentPrice + ' </font><font class="loss">' + percentChange.toFixed(1) + '%</font>');
} else { } else {
t.push('<font class="' + openOrClosed + '">' + i.DisplayName + '<br/>' + i.CurrentPrice + ' </font><font class="profit">+' + percentChange.toFixed(1) + '%</font>'); t.push('<font class="' + openOrClosed + '">' + label + '<br/>' + i.CurrentPrice + ' </font><font class="profit">+' + percentChange.toFixed(1) + '%</font>');
} }
} else { } else {
t.push('<font class="' + openOrClosed + '">' + i.DisplayName + '<br/>' + i.CurrentPrice + '</font>'); t.push('<font class="' + openOrClosed + '">' + label + '<br/>' + i.CurrentPrice + '</font>');
} }
} }
} }

View File

@ -0,0 +1,384 @@
'use strict';
import { formatAmount, getPercentCell } from "./SharePrices_Common.js";
/*
function createAccountsTables() {
function getAccounts() {
let accounts = [];
function indexOfAccount(accountName) { return accounts.map(function (item) { return item.accountName; }).indexOf(accountName); };
function getAccount(accountName) { return accounts[indexOfAccount(accountName)]; };
function addAccountHolding(instrument, exchangeRate, holding) {
let a = getAccount(holding.AccountName);
if (!a) {
a = { accountName: holding.AccountName, holdings: [], totalCostGBP: 0, totalValueGBP: 0, totalGainGBP: 0, totalCashGBP: 0 };
accounts.push(a);
}
let h = {
instrumentName: instrument.InstrumentName,
symbol: instrument.Symbol,
instrumentType: instrument.InstrumentType,
currency: instrument.Currency,
purchaseDate: holding.PurchaseDate,
purchasePricePerUnit: holding.PurchasePricePerUnit,
noUnits: holding.NoUnits,
cost: holding.NoUnits * holding.PurchasePricePerUnit
}
//if (exchangeRate) {
//h.costGBP = h.cost / exchangeRate;
h.costGBP = holding.BookCostGBP;
if (instrument.InstrumentType != 'CURRENCY') {
a.totalCostGBP += holding.BookCostGBP;
}
//}
if (instrument.CurrentPrice) {
h.currentPrice = instrument.CurrentPrice;
h.currentValue = holding.NoUnits * instrument.CurrentPrice;
h.gain = h.currentValue - h.cost;
if (exchangeRate) {
h.currentValueGBP = h.currentValue / exchangeRate;
//h.gainGBP = h.gain / exchangeRate;
h.gainGBP = h.currentValueGBP - h.costGBP;
if (instrument.InstrumentType != 'CURRENCY') {
a.totalGainGBP += h.gainGBP;
a.totalValueGBP += h.currentValueGBP;
}
}
}
if (instrument.InstrumentType == 'CURRENCY') {
//Don't add cash holdings - just add the cash value to the account
a.totalCashGBP += h.currentValueGBP;
} else {
a.holdings.push(h);
}
}
for (let ix = 0; ix < Instruments.Data.length; ix++) {
let i = Instruments.Data[ix];
let exchangegRate = Instruments.GetExchangeRate(i.Currency, 'GBP');
for (let hx = 0; hx < i.Holdings.length; hx++) {
let h = i.Holdings[hx];
if (h.SoldDate == null) {
addAccountHolding(i, exchangegRate, h);
}
}
}
return accounts;
}
let accounts = getAccounts();
//Sort the accounts array by accountName
accounts.sort(function (a, b) {
if (a.accountName < b.accountName) return -1;
if (a.accountName > b.accountName) return 1;
return 0;
});
//let summaryTable = "<table class='accounts' id='accountsSummaryTable'><thead><tr><th>Account Name</th><th>No. Holdings</th><th>Total Cost (GBP)</th><th>Current Value</th><th>Total Gain</th></tr></thead><tbody>";
let summaryTable = "<table class='accounts' id='accountsSummaryTable'><thead><tr>" +
"<th>Account Name</th>" +
"<th>No. Holdings</th>" +
"<th>Total Cost (GBP)</th>" +
"<th>Total Gains (GBP)</th>" +
"<th>Total Losses (GBP)</th>" +
"<th>Current Investements Value</th>" +
"<th>NET Gain</th>" +
"<th>Cash Balance GBP</th>" +
"<th>Total Value GBP</th>" +
"</tr></thead><tbody>";
let accountsTables = ''
let tableIDs = ['accountsSummaryTable'];
let hideEmptyAccounts = $('#hideEmptyAccounts').prop('checked');
let altRow = 1;
for (let ax = 0; ax < accounts.length; ax++) {
let a = accounts[ax];
let accountGainsGBP = 0;
let accountLossesGBP = 0;
let accountValueGBP = 0;
let profitOrLoss = a.totalGainGBP < 0 ? 'loss' : 'profit';
if (a.holdings.length > 0) {
altRow = !altRow;
accountsTables += '<br>' + a.accountName + '<br>'
let tableID = 'accountTable' + ax;
tableIDs.push(tableID);
accountsTables += '<table class="accounts" id="' + tableID + '">' +
'<thead><tr>' +
'<th>Name</th>' +
'<th>Symbol</th>' +
'<th>Buy Date</th>' +
'<th>No Units</th>' +
'<th>Buy Price</th>' +
'<th>Current Price</th>' +
'<th>Book Cost</th>' +
'<th>Approx Book Cost £</th>' +
'<th>Current Value</th>' +
'<th>Current Value £</th>' +
'<th>Gain</th>' +
'<th>Gain £</th>' +
'<th>Gain %</th>' +
'</tr></thead><tbody>';
let accountAltRow = 1;
for (let hx = 0; hx < a.holdings.length; hx++) {
let h = a.holdings[hx];
accountAltRow = !accountAltRow;
let holdingProfitOrLoss = h.gain < 0 ? 'loss' : 'profit';
let holdingGBPProfitOrLoss = h.gainGBP < 0 ? 'loss' : 'profit';
if (h.gainGBP > 0) {
accountGainsGBP += h.gainGBP;
} else {
accountLossesGBP += h.gainGBP;
}
accountValueGBP += h.currentValueGBP;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td>' + h.instrumentName + '</td>' +
'<td>' + h.symbol + '</td>' +
'<td>' + new Date(h.purchaseDate).yyyymmdd() + '</td>' +
'<td class="num">' + h.noUnits + '</td>' +
'<td class="num">' + formatAmount(h.purchasePricePerUnit, h.currency, 2) + '</td>' +
'<td class="num">' + formatAmount(h.currentPrice, h.currency, 2) + '</td>' +
'<td class="num">' + (h.currency == 'GBp' ? formatAmount(h.cost / 100, 'GBP', 2) : formatAmount(h.cost, h.currency, 2)) + '</td>' +
'<td class="num">' + formatAmount(h.costGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + (h.currency == 'GBp' ? formatAmount(h.currentValue / 100, 'GBP', 2) : formatAmount(h.currentValue, h.currency, 2)) + '</td>' +
'<td class="num">' + formatAmount(h.currentValueGBP, 'GBP', 2) + '</td>' +
'<td class="num ' + holdingProfitOrLoss + '">' + formatAmount(h.gain, h.currency, 2) + '</td>' +
'<td class="num ' + holdingGBPProfitOrLoss + '">' + formatAmount(h.gainGBP, 'GBP', 2) + '</td>' +
//'<td class="num ' + holdingProfitOrLoss + '">' + ((h.gain / h.cost) * 100).toFixed(1) + '%</td>' +
'<td class="num ' + holdingGBPProfitOrLoss + '">' + ((h.gainGBP / h.costGBP) * 100).toFixed(1) + '%</td>' +
'</tr>';
}
//Add the Total Gains
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="11">Total Gains</td>' +
'<td class="num profit">' + formatAmount(accountGainsGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
//Add the Total Losses
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="11">Total Losses</td>' +
'<td class="num loss">' + formatAmount(accountLossesGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
//Add the NET Gains summary line
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="9">Account Value:</td>' +
'<td class="num ' + ((accountGainsGBP + accountLossesGBP) > 0 ? 'profit' : 'loss') + '">' + formatAmount(accountValueGBP, 'GBP', 2) + '</td>' +
'<td class="num">NET Gain</td>' +
'<td class="num ' + ((accountGainsGBP + accountLossesGBP) > 0 ? 'profit' : 'loss') + '">' + formatAmount(accountGainsGBP + accountLossesGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
accountsTables += '</tbody></table>';
}
//Add an entry to the summary table
if (a.totalValueGBP + a.totalCashGBP > 0 || !hideEmptyAccounts) {
summaryTable += "<tr" + (altRow ? ' class="altShareRow"' : '') + "><td>" + a.accountName + "</td>" +
"<td>" + a.holdings.length + "</td>" +
"<td class='num'>" + formatAmount(a.totalCostGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(accountGainsGBP, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(accountLossesGBP, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalValueGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num " + profitOrLoss + "'>" + formatAmount(a.totalGainGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalCashGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalValueGBP + a.totalCashGBP || 0, 'GBP', 2) + "</td>" +
"</tr>";
}
}
summaryTable += "</tbody></table>";
$("#accountsSummaryDiv").html(summaryTable + '<br>' + accountsTables);
}
*/
export function createAccountsTables(Instruments) {
function getAccounts() {
let accounts = [];
function indexOfAccount(accountName) { return accounts.map(function (item) { return item.accountName; }).indexOf(accountName); };
function getAccount(accountName) { return accounts[indexOfAccount(accountName)]; };
function addAccountHolding(instrument, exchangeRate, holding) {
let a = getAccount(holding.AccountName);
if (!a) {
a = { accountName: holding.AccountName, holdings: [], totalCostGBP: 0, totalValueGBP: 0, totalGainGBP: 0, totalCashGBP: 0 };
accounts.push(a);
}
let h = {
instrumentName: instrument.InstrumentName,
symbol: instrument.Symbol,
instrumentType: instrument.InstrumentType,
currency: instrument.Currency,
purchaseDate: holding.PurchaseDate,
purchasePricePerUnit: holding.PurchasePricePerUnit,
noUnits: holding.NoUnits,
cost: holding.NoUnits * holding.PurchasePricePerUnit
}
//if (exchangeRate) {
//h.costGBP = h.cost / exchangeRate;
h.costGBP = holding.BookCostGBP;
if (instrument.InstrumentType != 'CURRENCY') {
a.totalCostGBP += holding.BookCostGBP;
}
//}
if (instrument.CurrentPrice) {
h.currentPrice = instrument.CurrentPrice;
h.currentValue = holding.NoUnits * instrument.CurrentPrice;
h.gain = h.currentValue - h.cost;
if (exchangeRate) {
h.currentValueGBP = h.currentValue / exchangeRate;
//h.gainGBP = h.gain / exchangeRate;
h.gainGBP = h.currentValueGBP - h.costGBP;
if (instrument.InstrumentType != 'CURRENCY') {
a.totalGainGBP += h.gainGBP;
a.totalValueGBP += h.currentValueGBP;
}
}
}
if (instrument.InstrumentType == 'CURRENCY') {
//Don't add cash holdings - just add the cash value to the account
a.totalCashGBP += h.currentValueGBP;
} else {
a.holdings.push(h);
}
}
for (let ix = 0; ix < Instruments.Data.length; ix++) {
let i = Instruments.Data[ix];
let exchangegRate = Instruments.GetExchangeRate(i.Currency, 'GBP');
for (let hx = 0; hx < i.Holdings.length; hx++) {
let h = i.Holdings[hx];
if (h.SoldDate == null) {
addAccountHolding(i, exchangegRate, h);
}
}
}
return accounts;
}
let accounts = getAccounts();
//Sort the accounts array by accountName
accounts.sort(function (a, b) {
if (a.accountName < b.accountName) return -1;
if (a.accountName > b.accountName) return 1;
return 0;
});
//let summaryTable = "<table class='accounts' id='accountsSummaryTable'><thead><tr><th>Account Name</th><th>No. Holdings</th><th>Total Cost (GBP)</th><th>Current Value</th><th>Total Gain</th></tr></thead><tbody>";
let summaryTable = "<table class='accounts' id='accountsSummaryTable'><thead><tr>" +
"<th>Account Name</th>" +
"<th>No. Holdings</th>" +
"<th>Total Cost (GBP)</th>" +
"<th>Total Gains (GBP)</th>" +
"<th>Total Losses (GBP)</th>" +
"<th>Current Investements Value</th>" +
"<th>NET Gain</th>" +
"<th>Cash Balance GBP</th>" +
"<th>Total Value GBP</th>" +
"</tr></thead><tbody>";
let accountsTables = ''
let tableIDs = ['accountsSummaryTable'];
let hideEmptyAccounts = $('#hideEmptyAccounts').prop('checked');
let altRow = 1;
for (let ax = 0; ax < accounts.length; ax++) {
let a = accounts[ax];
let accountGainsGBP = 0;
let accountLossesGBP = 0;
let accountValueGBP = 0;
let profitOrLoss = a.totalGainGBP < 0 ? 'loss' : 'profit';
if (a.holdings.length > 0) {
altRow = !altRow;
accountsTables += '<br>' + a.accountName + '<br>'
let tableID = 'accountTable' + ax;
tableIDs.push(tableID);
accountsTables += '<table class="accounts" id="' + tableID + '">' +
'<thead><tr>' +
'<th>Name</th>' +
'<th>Symbol</th>' +
'<th>Buy Date</th>' +
'<th>No Units</th>' +
'<th>Buy Price</th>' +
'<th>Current Price</th>' +
'<th>Book Cost</th>' +
'<th>Approx Book Cost £</th>' +
'<th>Current Value</th>' +
'<th>Current Value £</th>' +
'<th>Gain</th>' +
'<th>Gain £</th>' +
'<th>Gain %</th>' +
'</tr></thead><tbody>';
let accountAltRow = 1;
for (let hx = 0; hx < a.holdings.length; hx++) {
let h = a.holdings[hx];
accountAltRow = !accountAltRow;
let holdingProfitOrLoss = h.gain < 0 ? 'loss' : 'profit';
let holdingGBPProfitOrLoss = h.gainGBP < 0 ? 'loss' : 'profit';
if (h.gainGBP > 0) {
accountGainsGBP += h.gainGBP;
} else {
accountLossesGBP += h.gainGBP;
}
accountValueGBP += h.currentValueGBP;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td>' + h.instrumentName + '</td>' +
'<td>' + h.symbol + '</td>' +
'<td>' + new Date(h.purchaseDate).yyyymmdd() + '</td>' +
'<td class="num">' + h.noUnits + '</td>' +
'<td class="num">' + formatAmount(h.purchasePricePerUnit, h.currency, 2) + '</td>' +
'<td class="num">' + formatAmount(h.currentPrice, h.currency, 2) + '</td>' +
'<td class="num">' + (h.currency == 'GBp' ? formatAmount(h.cost / 100, 'GBP', 2) : formatAmount(h.cost, h.currency, 2)) + '</td>' +
'<td class="num">' + formatAmount(h.costGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + (h.currency == 'GBp' ? formatAmount(h.currentValue / 100, 'GBP', 2) : formatAmount(h.currentValue, h.currency, 2)) + '</td>' +
'<td class="num">' + formatAmount(h.currentValueGBP, 'GBP', 2) + '</td>' +
'<td class="num ' + holdingProfitOrLoss + '">' + formatAmount(h.gain, h.currency, 2) + '</td>' +
'<td class="num ' + holdingGBPProfitOrLoss + '">' + formatAmount(h.gainGBP, 'GBP', 2) + '</td>' +
//'<td class="num ' + holdingProfitOrLoss + '">' + ((h.gain / h.cost) * 100).toFixed(1) + '%</td>' +
'<td class="num ' + holdingGBPProfitOrLoss + '">' + ((h.gainGBP / h.costGBP) * 100).toFixed(1) + '%</td>' +
'</tr>';
}
//Add the Total Gains
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="11">Total Gains</td>' +
'<td class="num profit">' + formatAmount(accountGainsGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
//Add the Total Losses
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="11">Total Losses</td>' +
'<td class="num loss">' + formatAmount(accountLossesGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
//Add the NET Gains summary line
accountAltRow = !accountAltRow;
accountsTables += '<tr' + (accountAltRow ? ' class="altShareRow"' : '') + '>' +
'<td class="num" colspan="9">Account Value:</td>' +
'<td class="num ' + ((accountGainsGBP + accountLossesGBP) > 0 ? 'profit' : 'loss') + '">' + formatAmount(accountValueGBP, 'GBP', 2) + '</td>' +
'<td class="num">NET Gain</td>' +
'<td class="num ' + ((accountGainsGBP + accountLossesGBP) > 0 ? 'profit' : 'loss') + '">' + formatAmount(accountGainsGBP + accountLossesGBP, 'GBP', 2) + '</td>' +
'<td class="num">&nbsp;</td>' +
'</tr>';
accountsTables += '</tbody></table>';
}
//Add an entry to the summary table
if (a.totalValueGBP + a.totalCashGBP > 0 || !hideEmptyAccounts) {
summaryTable += "<tr" + (altRow ? ' class="altShareRow"' : '') + "><td>" + a.accountName + "</td>" +
"<td>" + a.holdings.length + "</td>" +
"<td class='num'>" + formatAmount(a.totalCostGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(accountGainsGBP, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(accountLossesGBP, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalValueGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num " + profitOrLoss + "'>" + formatAmount(a.totalGainGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalCashGBP || 0, 'GBP', 2) + "</td>" +
"<td class='num'>" + formatAmount(a.totalValueGBP + a.totalCashGBP || 0, 'GBP', 2) + "</td>" +
"</tr>";
}
}
summaryTable += "</tbody></table>";
$("#accountsSummaryDiv").html(summaryTable + '<br>' + accountsTables);
}

View File

@ -84,4 +84,13 @@ export function generateAxisBreaks(data, maxGapSize, breakSize) {
} }
} }
return breaks; return breaks;
} }
export function getPercentCell(backgroundColor, cellWidth, valuePercent, label) {
let labelText = label ? label : (valuePercent.toFixed(1) + '%');
let barWidth = ((valuePercent / 100) * cellWidth);
return '<td>' +
'<div class="pcBackground" style="background-color: ' + backgroundColor + '; width:' + barWidth.toFixed(0) + 'px;">&nbsp;</div>' +
'<div class="pcLabel" style="width:' + cellWidth + 'px">' + labelText + '</div>' +
'</td>';
}

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
import { formatAmount } from "./SharePrices_Common.js"; import { formatAmount, getPercentCell } from "./SharePrices_Common.js";
/*
export function createHoldingsTable(Instruments, vars) { export function createHoldingsTable(Instruments, vars) {
function getHoldings() { function getHoldings() {
function aggregateHoldings(i) { function aggregateHoldings(i) {
@ -302,12 +302,17 @@ export function createHoldingsTable(Instruments, vars) {
$('#holdingsTableDiv').html(tbl); $('#holdingsTableDiv').html(tbl);
$("#tblMainHoldings").tablesorter({ ignoreCase: false }); $("#tblMainHoldings").tablesorter({ ignoreCase: false });
$("#tblMainHoldings").trigger("sorton", Cookies.get('sortHoldings'));
//let sortOrder = Cookies.get('sortHoldings');
let sortOrder = JSON.parse(Cookies.get('sortHoldings'));
$("#tblMainHoldings").trigger("sorton", [sortOrder]);
$('#tblMainHoldings').on('sortEnd', function (event) { $('#tblMainHoldings').on('sortEnd', function (event) {
// Prints the current sort order to the console // Prints the current sort order to the console
if (event.target.config.sortList.length > 3) { if (event.target.config.sortList.length > 3) {
console.info({ "Setting sortHoldings Cookie (array too long?)": event.target.config.sortList }); console.info({ "Setting sortHoldings Cookie (array too long?)": event.target.config.sortList });
} }
//console.info({MSG: "Saving sortHolding cookie", Cookie: event.target.config.sortList});
Cookies.set('sortHoldings', event.target.config.sortList, { 'sameSite': 'strict' }); Cookies.set('sortHoldings', event.target.config.sortList, { 'sameSite': 'strict' });
}); });
} }
@ -354,14 +359,16 @@ export function createHoldingsTable(Instruments, vars) {
//$("#" + rowID).addClass("highlighted"); //$("#" + rowID).addClass("highlighted");
} }
} }
function getPercentCell(backgroundColor, cellWidth, valuePercent, label) {
let labelText = label ? label : (valuePercent.toFixed(1) + '%'); //function getPercentCell(backgroundColor, cellWidth, valuePercent, label) {
let barWidth = ((valuePercent / 100) * cellWidth); // let labelText = label ? label : (valuePercent.toFixed(1) + '%');
return '<td>' + // let barWidth = ((valuePercent / 100) * cellWidth);
'<div class="pcBackground" style="background-color: ' + backgroundColor + '; width:' + barWidth.toFixed(0) + 'px;">&nbsp;</div>' + // return '<td>' +
'<div class="pcLabel" style="width:' + cellWidth + 'px">' + labelText + '</div>' + // '<div class="pcBackground" style="background-color: ' + backgroundColor + '; width:' + barWidth.toFixed(0) + 'px;">&nbsp;</div>' +
'</td>'; // '<div class="pcLabel" style="width:' + cellWidth + 'px">' + labelText + '</div>' +
} // '</td>';
//}
function profitOrLoss(value) { function profitOrLoss(value) {
return value >= 0 ? "profit" : "loss"; return value >= 0 ? "profit" : "loss";
} }
@ -495,35 +502,6 @@ export function createHoldingsTable(Instruments, vars) {
var resort = true; var resort = true;
$("#tblMainHoldings").trigger("update", [resort]); $("#tblMainHoldings").trigger("update", [resort]);
//Update the daily holdings value table in the DB
if (totalValueGBP != vars.lastTotalHoldingsValue) {
$.ajax({
type: "POST",
contentType: "application/json",
url: "SharePrices.aspx/SetTotalHoldingsValue",
dataType: "json",
data: JSON.stringify({ TotalValue: totalValueGBP }),
success: function (response) {
vars.previousDay = response.PreviousDay;
vars.previousClose = response.PreviousClose;
vars.previousWeek = response.PreviousWeekDate;
vars.previousWeekClose = response.PreviousWeekClose;
//Update the total holdings span in the site banner
let formattedAmount = formatAmount(totalValueGBP, "GBP", 0);
let holdingsHTML = '<span style="font-size: small;">Total holdings:&nbsp;</span>' + '<span style="font-size: large">' + formattedAmount + '</span>&nbsp;';
holdingsHTML += '<span style="font-size: small;"><span class="' + (vars.previousClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousClose, "GBP", 0) + '</span>&nbsp;(d)';
holdingsHTML += '&nbsp;/&nbsp;<span class="' + (vars.previousWeekClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousWeekClose, "GBP", 0) + '</span>&nbsp;(w)</span>';
$("#spnTotalHoldings").html(holdingsHTML);
//Set the page title
document.title = formattedAmount + ' - ' + vars.initialPageTitle;
vars.lastTotalHoldingsValue = totalValueGBP;
},
failure: function (response) { console.error("SetTotalHoldingsValue error: " + JSON.stringify(response)); }
});
}
//Create / update the currency allocation pie chart //Create / update the currency allocation pie chart
function labelFormatter(label, series) { function labelFormatter(label, series) {
return "<div class='pieLabel'>" + label + "<br/>" + Math.round(series.percent) + "%<br>" + formatAmount(series.data[0][1], 'GBP', 0) + "</div>"; return "<div class='pieLabel'>" + label + "<br/>" + Math.round(series.percent) + "%<br>" + formatAmount(series.data[0][1], 'GBP', 0) + "</div>";
@ -589,3 +567,645 @@ function createCategoryAggregator() {
}; };
return aggregator; return aggregator;
} }
*/
export async function updateHoldingsTables(instruments, vars) {
createNewHoldingsTable(instruments, vars);
createAggregatedHoldingsTable(instruments, vars);
createWatchlistTable(instruments);
}
async function createNewHoldingsTable(instruments, vars) {
const noColumns = 16;
function createNewHoldingsTable() {
let table = $('#newHoldingsTable');
if (table.length == 0) {
let tblDef = '<table id="newHoldingsTable" class="mainHoldings">' +
getHeaderRow() +
'<tr id="newHoldingsTable_EndSpacer" class="mainHoldingsSpacer"><td colspan="' + noColumns.toString() + '">&nbsp;</td></tr>' +
'<tr id="newHoldingsTable_InvestmentsGrandTotals"><td colspan="' + noColumns.toString() + '">New Holdings Table Grand Totals Row</td></tr>' +
'<tr id="newHoldingsTable_CashTotal"><td colspan="' + noColumns.toString() + '">New Holdings Cash Total Row</td></tr>' +
'<tr id="newHoldingsTable_GrandTotal"><td colspan="' + noColumns.toString() + '">New Holdings Grand Total Row</td></tr>' +
'</table>';
$('#newHoldingsTableDiv').html(tblDef);
}
}
function createTaxBucketSubTable(taxBucket) {
let subtableID = 'taxBucket_' + taxBucket.replaceAll(' ', '_');
//let subtable = $('#' + subtableID);
let subtable = $('#' + subtableID + '_Summary');
if (subtable.length == 0) {
//let rowsDef = '<tr id="' + subtableID + '"><td colspan="' + noColumns.toString() + '">' + taxBucket + '</td></tr>\n' +
//let rowsDef = getHeaderRow() +
//let dt = (new Date()).yyyymmddhhmmss();
//let rowsDef = '<tr id="' + subtableID + '_Spacer"><td colspan="' + noColumns.toString() + '" class="mainHoldingsSpacer">&nbsp;' + dt + '</td></tr>\n' + //Spacer row
let rowsDef = '<tr id="' + subtableID + '_Summary" class="holdingsSubtotalRow"><td>&nbsp;</td></tr>'; //Sub Table Summary Row
//$(rowsDef).insertBefore('#newHoldingsTable_InvestmentsGrandTotals');
$(rowsDef).insertBefore('#newHoldingsTable_EndSpacer');
}
}
function getHeaderRow() {
return '<tr>' +
'<th>Account</th > ' +
'<th>Type</th > ' +
'<th>Name</th > ' +
'<th>Symbol</th > ' +
'<th>Ccy</th > ' +
'<th>No Units</th > ' +
'<th>Avg Buy<br/>Price</th > ' +
'<th>Previous<br/>Close</th > ' +
'<th>Current<br/>Price</th > ' +
'<th>Base Cost</th > ' +
'<th>Current Value</th > ' +
'<th>Gain</th > ' +
'<th>Gain %</th > ' +
'<th>Allocation</th > ' +
'<th>Today&apos;s<br/>Gain £</th>' +
'<th>Today&apos;s<br/>Gain %</th > ' +
'</tr>'
}
function getContentRow(row, instrument, scaledAllocation, allocationPercent) {
let openOrClosed = instruments.MarketIsOpen(instrument) == 1 ? 'open' : 'closed';
let rowID = 'newHoldingsRow_' + vars.currentHoldingsRows.rowID(row);
let type = row.InstrumentType == 'CURRENCY' ? '$' : row.InstrumentType.substring(0, 1);
let totalProfitOrLoss = row.UnrealisedGainGBP < 0 ? 'loss' : 'profit';
let todaysGainGBP = 0;
let todaysGainPct = 0;
let todaysProfitOrLoss = 'profit';
if (instrument.SingleDayPreviousClose) {
todaysGainGBP = (row.CurrentPriceGBP - (instrument.SingleDayPreviousClose / row.CurrentExchangeRate)) * row.NoUnits;
todaysGainPct = ((row.CurrentPriceGBP / (instrument.SingleDayPreviousClose / row.CurrentExchangeRate)) - 1) * 100;
todaysProfitOrLoss = todaysGainGBP < 0 ? 'loss' : 'profit';
}
let cryptoHoldingClass = instrument.InstrumentType == 'CRYPTOCURRENCY' ? ' cryptoHoldingRow' : '';
return '<tr id="' + rowID + '" class="holdingsRow ' + openOrClosed + cryptoHoldingClass + '">' +
'<td>' + row.AccountName + '</td>' +
'<td>' + type + '</td>' +
'<td>' + row.InstrumentName + '</td>' +
//'<td>' + row.Symbol + '</td>' +
'<td><a target="_blank" href="https://uk.finance.yahoo.com/quote/' + instrument.Symbol + '">' + instrument.Symbol + '</a>' + '</td>' +
'<td>' + row.InstrumentCurrency + '</td>' +
'<td class="num">' + row.NoUnits.autoScale() + '</td>' +
'<td class="num">' + formatAmount(row.AvgPriceGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(instrument.SingleDayPreviousClose / row.CurrentExchangeRate, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(row.CurrentPriceGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(row.BaseCostGBP, 'GBP', 0) + '</td>' +
'<td class="num">' + formatAmount(row.CurrentValueGBP, 'GBP', 0) + '</td>' +
'<td class="num ' + totalProfitOrLoss + '">' + formatAmount(row.UnrealisedGainGBP, 'GBP', 0) + '</td>' +
'<td class="num ' + totalProfitOrLoss + '">' + formatAmount(row.UnrealisedGainPct, '', 1) + '%</td>' + //Gain %
//'<td>' + '&nbsp;' + '</td>' + //Allocation
getPercentCell('#280ea6' /*'#3f2d95'*/, 70, scaledAllocation, allocationPercent.toFixed(1) + '%') + //Allocation
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainGBP == 0) ? '&nbsp;' : formatAmount(todaysGainGBP, 'GBP', 0)) + '</td>' + //Today's Gain £
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainPct == 0) ? '&nbsp;' : formatAmount(todaysGainPct, '', 1) + '%') + '</td>' + //Today's Gain %
'</tr>'
}
function updateTaxBucketSubtotals(taxBucket, baseCostGBP, currentValueGBP, todaysGain) {
let subtableID = 'taxBucket_' + taxBucket.replaceAll(' ', '_');
let rowID = subtableID + '_Summary';
let profitOrLoss = currentValueGBP < baseCostGBP ? 'loss' : 'profit';
let rowDef = '<tr id="' + subtableID + '_Summary" class="holdingsSubtotal">' +
'<td colspan="9" class="num">' + taxBucket + ' Sutotal</td>' +
'<td class="num">' + formatAmount(baseCostGBP, 'GBP', 2) + '</td>' + //BaseCost
'<td class="num">' + formatAmount(currentValueGBP, 'GBP', 2) + '</td>' + //CurrentValue
'<td class="num ' + profitOrLoss + '">' + formatAmount(currentValueGBP - baseCostGBP, 'GBP', 0) + '</td>' + //GainGBP
'<td class="num ' + profitOrLoss + '">' + formatAmount((currentValueGBP - baseCostGBP) / baseCostGBP * 100, '', 1) + '%</td>' + //Gain%
'<td>&nbsp;</td>' +
'<td class="num ' + (todaysGain < 0 ? 'loss' : 'profit') + '">' + (todaysGain == 0 ? '&nbsp;' : formatAmount(todaysGain, 'GBP', 0)) + '</td>' +
'<td>&nbsp;</td>' +
'</tr>';
$('#' + rowID).replaceWith(rowDef);
}
function updateInvestmentsGrandTotals(totalBaseCostGBP, totalCurrentValueGBP, todaysGain) {
let profitOrLoss = totalCurrentValueGBP < totalBaseCostGBP ? 'loss' : 'profit';
let rowID = 'newHoldingsTable_InvestmentsGrandTotals';
let rowDef = '<tr id="' + rowID + '">' +
'<td colspan="9" class="num holdingsGrandTotal">Investments Total</td>' +
'<td class="num">' + formatAmount(totalBaseCostGBP, 'GBP', 0) + '</td>' + //BaseCost
'<td class="num">' + formatAmount(totalCurrentValueGBP, 'GBP', 0) + '</td>' + //CurrentValue
'<td class="num ' + profitOrLoss + '">' + formatAmount(totalCurrentValueGBP - totalBaseCostGBP, 'GBP', 0) + '</td>' + //GainGBP
'<td class="num ' + profitOrLoss + '">' + formatAmount((totalCurrentValueGBP - totalBaseCostGBP) / totalBaseCostGBP * 100, '', 1) + '%</td>' + //Gain%
'<td>&nbsp;</td>' +
'<td class="num ' + (todaysGain < 0 ? 'loss' : 'profit') + '">' + (todaysGain == 0 ? '&nbsp;' : formatAmount(todaysGain, 'GBP', 0)) + '</td>' +
'<td>&nbsp;</td>' +
'</tr>';
$('#' + rowID).replaceWith(rowDef);
}
function updateCashTotal(totalCashGBP) {
let rowID = 'newHoldingsTable_CashTotal';
//let rowDef = '<tr id="' + rowID + '" class="holdingsGrandTotal">' +
let rowDef = '<tr id="' + rowID + '">' +
'<td colspan="9" class="num holdingsGrandTotal">Cash Total</td>' +
'<td>&nbsp;</td>' +
'<td class="num">' + formatAmount(totalCashGBP, 'GBP', 0) + '</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'</tr>';
$('#' + rowID).replaceWith(rowDef);
}
function updateGrandTotal(grandTotalGBP) {
let rowID = 'newHoldingsTable_GrandTotal';
let rowDef = '<tr id="' + rowID + '">' +
'<td colspan="9" class="num holdingsGrandTotal">Grand Total</td>' +
'<td>&nbsp;</td>' +
'<td class="num">' + formatAmount(grandTotalGBP, 'GBP', 0) + '</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'</tr>';
$('#' + rowID).replaceWith(rowDef);
}
function updateTableRow(row, newContent) {
let rowID = 'newHoldingsRow_' + vars.currentHoldingsRows.rowID(row).replaceAll('.', '\\.');
let tr = $('#' + rowID);
if (tr.length > 0) {
//Row exists... update content
$(tr).replaceWith(newContent);
} else {
//Need to add row
createNewHoldingsTable();
createTaxBucketSubTable(row.TaxBucket);
$(newContent).insertBefore('#taxBucket_' + row.TaxBucket.replaceAll(' ', '_') + '_Summary');
}
//Add the highlighted class so the updated row will flash
$('#' + rowID).addClass("highlighted");
}
let holdings = {};
try {
holdings = await $.ajax({
type: "POST",
contentType: "application/json",
url: "SharePrices.aspx/GetCurrentHoldings"
});
}
catch (error) {
console.error({ MSG: "Error getting current holdings", Error: error });
}
//Save the current holdings for use elsewehere
vars.currentHoldings = holdings;
//Calculate totals before creating table rows
let totalCashGBP = 0;
let totalBaseCost = 0;
let totalCurrentValue = 0;
let maxCurrentValue = 0;
for (let rowNo = 0; rowNo < holdings.length; rowNo++) {
let r = holdings[rowNo];
if(r.InstrumentType == 'CURRENCY') {
totalCashGBP += r.CurrentValueGBP;
} else {
totalBaseCost += r.BaseCostGBP;
totalCurrentValue += r.CurrentValueGBP;
if (r.CurrentValueGBP > maxCurrentValue) maxCurrentValue = r.CurrentValueGBP;
}
}
let maxAllocationPercent = (maxCurrentValue / totalCurrentValue) * 100;
let allocationScaleFactor = 100 / maxAllocationPercent;
//Create the holdings table rows
let currentTaxBucket = '';
let bucketBaseCost = 0;
let bucketCurrentValue = 0;
let bucketTodaysGain = 0;
let totalTodaysGain = 0;
for (let rowNo = 0; rowNo < holdings.length; rowNo++) {
let r = holdings[rowNo];
if(r.InstrumentType != 'CURRENCY') {
let instrument = instruments.GetSymbol(r.Symbol);
let allocationPercent = r.CurrentValueGBP / totalCurrentValue * 100;
let scaledAllocation = allocationScaleFactor * allocationPercent;
if (r.TaxBucket != currentTaxBucket) {
if (currentTaxBucket != '') {
//Update the subtotal row for the previous tax bucket
updateTaxBucketSubtotals(currentTaxBucket, bucketBaseCost, bucketCurrentValue, bucketTodaysGain);
}
currentTaxBucket = r.TaxBucket;
bucketBaseCost = 0;
bucketCurrentValue = 0;
bucketTodaysGain = 0;
}
bucketBaseCost += r.BaseCostGBP;
bucketCurrentValue += r.CurrentValueGBP;
let todaysGain = instrument.SingleDayPreviousClose ? (r.CurrentPriceGBP - (instrument.SingleDayPreviousClose / r.CurrentExchangeRate)) * r.NoUnits : 0;
bucketTodaysGain += todaysGain;
totalTodaysGain += todaysGain;
//Has this row changed?
let currentRow = vars.currentHoldingsRows.GetRow(r);
let newContent = getContentRow(r, instrument, scaledAllocation, allocationPercent);
if (!currentRow) {
vars.currentHoldingsRows.Data.push({ attributes: r, content: newContent });
updateTableRow(r, newContent);
} else if (currentRow.content != newContent) {
currentRow.attributes = r;
currentRow.content = newContent;
updateTableRow(r, newContent);
}
}
/*
TaxBucket
AccountName
IsTaxable
InstrumentType
Symbol
InstrumentName
InstrumentCurrency
NoUnits
BaseCostGBP
AvgPriceGBP
CurrentPriceGBP
CurrentValueGBP
UnrealisedGainGBP
*/
}
let totalValueGBP = totalCurrentValue + totalCashGBP;
updateTaxBucketSubtotals(currentTaxBucket, bucketBaseCost, bucketCurrentValue, bucketTodaysGain);
updateInvestmentsGrandTotals(totalBaseCost, totalCurrentValue, totalTodaysGain);
updateCashTotal(totalCashGBP);
updateGrandTotal(totalValueGBP);
//Show or hide the Tax Bucket subtotals
let subtotalsDisplay = Cookies.get('showSubtotals');
if (subtotalsDisplay == 'true') {
$("#newHoldingsTable tr.holdingsSubtotal").show();
} else {
$("#newHoldingsTable tr.holdingsSubtotal").hide();
}
//Show or hide cryptocurrency holdings
let cryptoDisplay = Cookies.get('showCryptoHoldings');
if (cryptoDisplay == 'true') {
$("#newHoldingsTable tr.cryptoHoldingRow").show();
} else {
$("#newHoldingsTable tr.cryptoHoldingRow").hide();
}
//Remove the highlight from all rows/cells
$("#newHoldingsTable").find(".highlighted").removeClass("highlighted", 1200);
//Update the daily holdings value table in the DB
if (totalValueGBP > 0 && totalValueGBP != vars.lastTotalHoldingsValue) {
$.ajax({
type: "POST",
contentType: "application/json",
url: "SharePrices.aspx/SetTotalHoldingsValue",
dataType: "json",
data: JSON.stringify({ TotalValue: totalValueGBP }),
success: function (response) {
vars.previousDay = response.PreviousDay;
vars.previousClose = response.PreviousClose;
vars.previousWeek = response.PreviousWeekDate;
vars.previousWeekClose = response.PreviousWeekClose;
//Update the total holdings span in the site banner
let formattedAmount = formatAmount(totalValueGBP, "GBP", 0);
let holdingsHTML = '<span style="font-size: small;">Total holdings:&nbsp;</span>' + '<span style="font-size: large">' + formattedAmount + '</span>&nbsp;';
holdingsHTML += '<span style="font-size: small;"><span class="' + (vars.previousClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousClose, "GBP", 0) + '</span>&nbsp;(d)';
holdingsHTML += '&nbsp;/&nbsp;<span class="' + (vars.previousWeekClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousWeekClose, "GBP", 0) + '</span>&nbsp;(w)</span>';
$("#spnTotalHoldings").html(holdingsHTML);
//Set the page title
document.title = formattedAmount + ' - ' + vars.initialPageTitle;
vars.lastTotalHoldingsValue = totalValueGBP;
},
failure: function (response) { console.error("SetTotalHoldingsValue error: " + JSON.stringify(response)); }
});
}
}
async function createAggregatedHoldingsTable(instruments, vars) {
const noColumns = 15;
function createAggHoldingsTable() {
let table = $('#aggHoldingsTable');
if (table.length == 0) {
let tblDef = '<table id="aggHoldingsTable" class="mainHoldings">' +
getHeaderRow() +
'<tr id="aggHoldingsTable_EndSpacer" class="mainHoldingsSpacer"><td colspan="' + noColumns.toString() + '">&nbsp;</td></tr>' +
'<tr id="aggHoldingsTable_InvestmentsGrandTotals"><td colspan="' + noColumns.toString() + '">Aggregated Holdings Table Grand Totals Row</td></tr>' +
'<tr id="aggHoldingsTable_CashTotal"><td colspan="' + noColumns.toString() + '">Aggregated Holdings Cash Total Row</td></tr>' +
'<tr id="aggHoldingsTable_GrandTotal"><td colspan="' + noColumns.toString() + '">Aggregated Holdings Grand Total Row</td>' +
'</tr>' +
'</table>';
$('#aggHoldingsTableDiv').html(tblDef);
}
}
function getHeaderRow() {
return '<tr>' +
'<th>Type</th > ' +
'<th>Name</th > ' +
'<th>Symbol</th > ' +
'<th>Ccy</th > ' +
'<th>No Units</th > ' +
'<th>Avg Buy<br/>Price</th > ' +
'<th>Previous<br/>Close</th > ' +
'<th>Current<br/>Price</th > ' +
'<th>Base Cost</th > ' +
'<th>Current Value</th > ' +
'<th>Gain</th > ' +
'<th>Gain %</th > ' +
'<th>Allocation</th > ' +
'<th>Today&apos;s<br/>Gain £</th>' +
'<th>Today&apos;s<br/>Gain %</th > ' +
'</tr>'
}
function getContentRow(row, instrument, scaledAllocation, allocationPercent) {
let openOrClosed = instruments.MarketIsOpen(instrument) == 1 ? 'open' : 'closed';
let rowID = 'aggHoldingsRow_' + vars.currentAggHoldingsRows.rowID(row);
let type = row.InstrumentType == 'CURRENCY' ? '$' : row.InstrumentType.substring(0, 1);
let totalProfitOrLoss = row.UnrealisedGainGBP < 0 ? 'loss' : 'profit';
let todaysGainGBP = 0;
let todaysGainPct = 0;
let todaysProfitOrLoss = 'profit';
if (instrument.SingleDayPreviousClose) {
todaysGainGBP = (row.CurrentPriceGBP - (instrument.SingleDayPreviousClose / row.CurrentExchangeRate)) * row.NoUnits;
todaysGainPct = ((row.CurrentPriceGBP / (instrument.SingleDayPreviousClose / row.CurrentExchangeRate)) - 1) * 100;
todaysProfitOrLoss = todaysGainGBP < 0 ? 'loss' : 'profit';
}
return '<tr id="' + rowID + '" class="holdingsRow ' + openOrClosed + '">' +
'<td>' + type + '</td>' +
'<td>' + row.InstrumentName + '</td>' +
//'<td>' + row.Symbol + '</td>' +
'<td><a target="_blank" href="https://uk.finance.yahoo.com/quote/' + instrument.Symbol + '">' + instrument.Symbol + '</a>' + '</td>' +
'<td>' + row.InstrumentCurrency + '</td>' +
'<td class="num">' + row.NoUnits.autoScale() + '</td>' +
'<td class="num">' + formatAmount(row.AvgPriceGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(instrument.SingleDayPreviousClose / row.CurrentExchangeRate, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(row.CurrentPriceGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(row.BaseCostGBP, 'GBP', 0) + '</td>' +
'<td class="num">' + formatAmount(row.CurrentValueGBP, 'GBP', 0) + '</td>' +
'<td class="num ' + totalProfitOrLoss + '">' + formatAmount(row.UnrealisedGainGBP, 'GBP', 0) + '</td>' +
'<td class="num ' + totalProfitOrLoss + '">' + formatAmount(row.UnrealisedGainPct, '', 1) + '%</td>' + //Gain %
//'<td>' + '&nbsp;' + '</td>' + //Allocation
getPercentCell('#280ea6' /*'#3f2d95'*/, 70, scaledAllocation, allocationPercent.toFixed(1) + '%') + //Allocation
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainGBP == 0) ? '&nbsp;' : formatAmount(todaysGainGBP, 'GBP', 0)) + '</td>' + //Today's Gain £
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainPct == 0) ? '&nbsp;' : formatAmount(todaysGainPct, '', 1) + '%') + '</td>' + //Today's Gain %
'</tr>'
}
function updateInvestmentsGrandTotals(totalBaseCostGBP, totalCurrentValueGBP, todaysGain) {
let profitOrLoss = totalCurrentValueGBP < totalBaseCostGBP ? 'loss' : 'profit';
let rowID = 'aggHoldingsTable_InvestmentsGrandTotals';
let rowDef = '<tr id="' + rowID + '">' +
'<td colspan="8" class="num holdingsGrandTotal">Investments Total</td>' +
'<td class="num">' + formatAmount(totalBaseCostGBP, 'GBP', 0) + '</td>' + //BaseCost
'<td class="num">' + formatAmount(totalCurrentValueGBP, 'GBP', 0) + '</td>' + //CurrentValue
'<td class="num ' + profitOrLoss + '">' + formatAmount(totalCurrentValueGBP - totalBaseCostGBP, 'GBP', 0) + '</td>' + //GainGBP
'<td class="num ' + profitOrLoss + '">' + formatAmount((totalCurrentValueGBP - totalBaseCostGBP) / totalBaseCostGBP * 100, '', 1) + '%</td>' + //Gain%
'<td>&nbsp;</td>' +
'<td class="num ' + (todaysGain < 0 ? 'loss' : 'profit') + '">' + (todaysGain == 0 ? '&nbsp;' : formatAmount(todaysGain, 'GBP', 0)) + '</td>' +
'<td>&nbsp;</td>' +
'</tr>';
$('#' + rowID).replaceWith(rowDef);
}
function updateCashTotal(totalCashGBP) {
let rowID = 'aggHoldingsTable_CashTotal';
let rowDef = '<tr id="' + rowID + '">' +
'<td colspan="8" class="num holdingsGrandTotal">Cash Total</td>' +
'<td>&nbsp;</td>' +
'<td class="num">' + formatAmount(totalCashGBP, 'GBP', 0) + '</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'</tr>';
$('#' + rowID).replaceWith(rowDef);
}
function updateGrandTotal(grandTotalGBP) {
let rowID = 'aggHoldingsTable_GrandTotal';
let lSF = '';
if (vars.fetchTiming.lastSuccessfulFetch) {
let lastFetchAge = ((new Date()) - vars.fetchTiming.lastSuccessfulFetch);
let staleFetch = ((new Date()) - vars.fetchTiming.lastSuccessfulFetch) > (vars.fetchTiming.fetchIntervalSingleDay * 1.5);
lSF = (vars.fetchTiming.lastSuccessfulFetch ? ' - Last Successful Fetch: ' + (staleFetch ? '<span class="loss">' : '') + vars.fetchTiming.lastSuccessfulFetch.yyyymmddhhmmss() + (staleFetch ? '</span>' : '') : '');
}
//let lastUpdatedCell = '<td id="aggHoldingsLastUpdated" class="highlighted" colspan="6">Updated: ' + new Date().yyyymmddhhmmss() + lSF + '</td>';
let rowDef = '<tr id="' + rowID + '">' +
//'<td colspan="8" class="num">Grand Total</td>' +
'<td id="aggHoldingsLastUpdated" class="highlighted" colspan="7">Updated: ' + new Date().yyyymmddhhmmss() + lSF + '</td>' +
'<td class="num holdingsGrandTotal">Grand Total</td>' +
'<td>&nbsp;</td>' +
'<td class="num">' + formatAmount(grandTotalGBP, 'GBP', 0) + '</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'<td>&nbsp;</td>' +
'</tr>';
$('#' + rowID).replaceWith(rowDef);
}
function updateTableRow(row, newContent) {
let rowID = 'aggHoldingsRow_' + vars.currentAggHoldingsRows.rowID(row).replaceAll('.', '\\.');
let tr = $('#' + rowID);
if (tr.length > 0) {
//Row exists... update content
$(tr).replaceWith(newContent);
} else {
//Need to add row
createAggHoldingsTable();
//$(newContent).insertBefore('#aggHoldingsTable_InvestmentsGrandTotals');
$(newContent).insertBefore('#aggHoldingsTable_EndSpacer');
}
//Add the highlighted class so the updated row will flash
$('#' + rowID).addClass("highlighted");
}
let holdings = {};
try {
holdings = await $.ajax({
type: "POST",
contentType: "application/json",
url: "SharePrices.aspx/GetAggregatedCurrentHoldings"
});
}
catch (error) {
console.error({ MSG: "Error getting aggregated current holdings", Error: error });
}
//Calculate totals before creating table rows
let totalCashGBP = 0;
let totalBaseCost = 0;
let totalCurrentValue = 0;
let maxCurrentValue = 0;
for (let rowNo = 0; rowNo < holdings.length; rowNo++) {
let r = holdings[rowNo];
if (r.InstrumentType == 'CURRENCY') {
totalCashGBP += r.CurrentValueGBP;
} else {
totalBaseCost += r.BaseCostGBP;
totalCurrentValue += r.CurrentValueGBP;
if (r.CurrentValueGBP > maxCurrentValue) maxCurrentValue = r.CurrentValueGBP;
}
}
let maxAllocationPercent = (maxCurrentValue / totalCurrentValue) * 100;
let allocationScaleFactor = 100 / maxAllocationPercent;
//Create the holdings table rows
let totalTodaysGain = 0;
for (let rowNo = 0; rowNo < holdings.length; rowNo++) {
let r = holdings[rowNo];
if (r.InstrumentType != 'CURRENCY') {
let instrument = instruments.GetSymbol(r.Symbol);
let allocationPercent = r.CurrentValueGBP / totalCurrentValue * 100;
let scaledAllocation = allocationScaleFactor * allocationPercent;
let todaysGain = instrument.SingleDayPreviousClose ? (r.CurrentPriceGBP - (instrument.SingleDayPreviousClose / r.CurrentExchangeRate)) * r.NoUnits : 0;
totalTodaysGain += todaysGain;
//Has this row changed?
let currentRow = vars.currentAggHoldingsRows.GetRow(r);
let newContent = getContentRow(r, instrument, scaledAllocation, allocationPercent);
if (!currentRow) {
vars.currentAggHoldingsRows.Data.push({ attributes: r, content: newContent });
updateTableRow(r, newContent);
} else if (currentRow.content != newContent) {
currentRow.attributes = r;
currentRow.content = newContent;
updateTableRow(r, newContent);
}
}
/*
InstrumentType
Symbol
InstrumentName
InstrumentCurrency
NoUnits
BaseCostGBP
AvgPriceGBP
CurrentPriceGBP
CurrentValueGBP
UnrealisedGainGBP
*/
}
let totalValueGBP = totalCurrentValue + totalCashGBP;
updateInvestmentsGrandTotals(totalBaseCost, totalCurrentValue, totalTodaysGain);
updateCashTotal(totalCashGBP);
updateGrandTotal(totalValueGBP);
/*
//Show or hide the Tax Bucket subtotals
let subtotalsDisplay = Cookies.get('showSubtotals');
if (subtotalsDisplay == 'true') {
$("#newHoldingsTable tr.holdingsSubtotal").show();
} else {
$("#newHoldingsTable tr.holdingsSubtotal").hide();
}
*/
//Remove the highlight from all rows/cells
$("#aggHoldingsTable").find(".highlighted").removeClass("highlighted", 1200);
}
function createWatchlistTable(Instruments) {
function addTableRow(rowID, content, tbodyID, highlightUpdates) {
let r = $("#" + rowID);
let newText = $(content).text(); //$(content).text();
if (r.length) {
let currentContent = r.text();
if (currentContent != newText) { //Only update row if the content has changed
$("#" + rowID).replaceWith(content);
if (highlightUpdates) {
$("#" + rowID).addClass("highlighted");
}
}
} else {
$("#" + tbodyID).append(content); //.addClass("highlighted");
//$("#" + rowID).addClass("highlighted");
}
}
let t = $("#tblWatchlist");
if (!t.length) /*
return;
} else */{
let tbl = '<table id="tblWatchlist" class="watchlist"><thead>' +
'<tr><th>Type</th>' +
'<th>Name</th>' +
'<th>Symbol</th>' +
'<th>Ccy</th>' +
'<th>Current Price</th>' +
'<th>Today&apos;s Gain</th>' +
'<th>Today&apos;s Gain %</th>' +
'<th>Since Last Sold<th>' +
'</tr></thead><tbody id="tbWatchlist"></tbody></table>';
$('#watchlistTableDiv').html(tbl);
$("#tblWatchlist").tablesorter({ ignoreCase: false });
$("#tblWatchlist").trigger("sorton", Cookies.get('sortWatchlist'));
$('#tblWatchlist').on('sortEnd', function (event) {
// Prints the current sort order to the console
Cookies.set('sorWatchlist', event.target.config.sortList, { 'sameSite': 'strict' });
});
}
let altRow = 1;
for (let n = 0; n < Instruments.Data.length; n++) {
if (Instruments.Data[n].WatchlistID) {
altRow = !altRow;
let wi = Instruments.Data[n];
try {
let type = wi.InstrumentType == 'CURRENCY' ? '$' : wi.InstrumentType.substring(0, 1);
let openOrClosed = Instruments.MarketIsOpen(wi) == 1 ? 'open' : 'closed';
let profitOrLoss = wi.CurrentPrice < wi.SingleDayPreviousClose ? 'loss' : 'profit';
let rowID = "watchlistRow_" + wi.DisplayOrder;
let sinceLastSold = '<td></td>';
if (wi.LastSoldPrice) {
let delta = (wi.CurrentPrice - wi.LastSoldPrice) / wi.LastSoldPrice * 100;
let tooltip = new Date(wi.LastSoldDate).yyyymmdd() + ' @ ' + wi.LastSoldPrice.toFixed(2);
sinceLastSold = '<td title="' + tooltip + '" class="num ' + (delta < 0 ? 'loss' : 'profit') + '">' + (delta).toFixed(1) + '%</td>';
}
//Type, Name, Symbol, Ccy, Current Price, Today's Gain, Today's Gain %
let row = '<tr' + (altRow ? ' class="altShareRow"' : '') + ' id="' + rowID + '">' +
'<td class="' + openOrClosed + '">' + type + '</td>' +
//'<td class="' + openOrClosed + '">' + wi.InstrumentName + '</td>' +
'<td class="' + openOrClosed + '">' + wi.DisplayName + '</td>' +
'<td><a target="_blank" href="https://uk.finance.yahoo.com/quote/' + wi.Symbol + '">' + wi.Symbol + '</a>' + '</td>' +
'<td class="' + openOrClosed + '">' + wi.Currency + '</td>' +
'<td class="num ' + openOrClosed + '">' + (wi.CurrentPrice ? formatAmount(wi.CurrentPrice, wi.Currency, 2) : '') + '</td>' + //Current Price
(Instruments.marketIsOpen == 0 ? '<td/>' : '<td class="num ' + profitOrLoss + '">' + (wi.CurrentPrice ? formatAmount(wi.CurrentPrice - wi.SingleDayPreviousClose, wi.Currency, 2) : '') + '</td>') + //Today's Gain
(Instruments.marketIsOpen == 0 ? '<td/>' : '<td class="num ' + profitOrLoss + '">' + (wi.CurrentPrice ? ((wi.CurrentPrice - wi.SingleDayPreviousClose) / wi.SingleDayPreviousClose * 100).toFixed(1) : '') + '</td>') + //Today's Gain %
//'<td>' + (new Date(wi.LastSoldDate)).yyyymmdd() + '</td>' +
sinceLastSold +
'</tr>';
addTableRow(rowID, row, "tbWatchlist", true);
}
catch (err) {
logError("Error adding " + wi.symbol + " to watchlist table: " + err.message);
}
}
}
//Remove the highlight from all rows/cells
$("#tbWatchlist").find(".highlighted").removeClass("highlighted", 1200);
}

View File

@ -0,0 +1,117 @@
'use strict';
import { formatAmount, getPercentCell } from "./SharePrices_Common.js";
export async function updateLedgerTable(instruments, vars) {
const noColumns = 15;
function createLedgerTable() {
let table = $('#ledgerTable');
//if (table.length == 0) {
let tblDef = '<table id="ledgerTable" class="ledger">' +
'<thead>' + getHeaderRow() + '</thead>' +
'<tbody></tbody>' +
'</table>';
$('#ledgerDiv').html(tblDef);
//}
}
function getHeaderRow() {
return '<tr>' +
'<th>Trade DT</th>' +
'<th>Tax Bucket</th>' +
'<th>Account</th>' +
'<th>Symbol</th>' +
'<th>Instrument Name</th>' +
//'<th>Instrument Currency</th>' +
'<th>Action<br/>Type</th>' +
//'<th>No Units</th>' +
//'<th>Price Per Unit GBP</th>' +
'<th>Units</th>' +
'<th>Trade<br/>Value</th>' +
'<th>New Pool<br/>Total Units</th>' +
'<th>New Pool<br/>Base Cost</th>' +
'<th>Realised<br/>Gain</th>' +
'<th>Is Final<br/>Position</th>' +
'<th>Notes</th>' +
'</tr>'
}
function getContentRow(row) {
let rowID = 'ledgerRow_' + row.TradeLedgerID.toString();
return '<tr id="' + rowID + '" class="ledgerRow">' +
'<td>' + (new Date(row.TradeDT)).yyyymmddhhmm() + '</td>' +
'<td>' + row.TaxBucket + '</td>' +
'<td>' + row.AccountName + '</td>' +
'<td>' + row.Symbol + '</td>' +
'<td>' + row.InstrumentName + '</td>' +
//'<td>' + row.InstrumentCurrency + '</td>' +
'<td>' + row.ActionType + '</td>' +
//'<td class="num">' + row.NoUnits.autoScale() + '</td>' +
//'<td class="num">' + formatAmount(row.PricePerUnitGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + row.NoUnits.autoScale() + ' @ ' + formatAmount(row.PricePerUnitGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(row.TradeValueGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + row.NewPoolTotalUnits.autoScale() + '</td>' +
'<td class="num">' + formatAmount(row.NewPoolBaseCostGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + formatAmount(row.RealisedGainGBP, 'GBP', 2) + '</td>' +
'<td class="num">' + row.IsFinalPosition.toString() + '</td>' +
'<td>' + (row.Notes == null ? '' : row.Notes) + '</td>' +
'</tr>'
}
//Fetch the ledger data
let ledger = {};
try {
ledger = await $.ajax({
type: "POST",
contentType: "application/json",
url: "SharePrices.aspx/GetTradeHistory"
});
}
catch (error) {
console.error({ MSG: "Error getting trade history", Error: error });
}
createLedgerTable();
//Create the ledger table rows
for (let rowNo = 0; rowNo < ledger.length; rowNo++) {
let r = ledger[rowNo];
let newContent = getContentRow(r);
$("#ledgerTable tbody").append(newContent);
}
//Add the tableSorter filter widget
let $table = $("#ledgerTable").tablesorter({
//theme: 'blue',
// this is the default setting
//cssChildRow: "tablesorter-childRow",
// initialize zebra and filter widgets
widgets: ["zebra", "filter", "stickyHeaders"],
widgetOptions: {
// output default: '{page}/{totalPages}'
// possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows}
//pager_output: '{startRow} - {endRow} / {filteredRows} ({totalRows})',
//pager_removeRows: false,
// include child row content while filtering, if true
//filter_childRows: true,
// class name applied to filter row and each input
/*filter_cssFilter: 'tablesorter-filter',
filter_filteredRow: 'filtered',
// search from beginning
filter_startsWith: false,
// Set this option to false to make the searches case sensitive
filter_ignoreCase: true,
*/
stickyHeaders_attachTo: '#ledgerDiv',
//stickyHeaders_zIndex: 2,
zebra: [ 'odd', 'even']
}
});
}