Added Ledger, started removing Holdings
This commit is contained in:
parent
e4f6c3d707
commit
5516aa1362
1026
Websites/SharePrices/.vs/SharePrices/config/applicationhost.config
Normal file
1026
Websites/SharePrices/.vs/SharePrices/config/applicationhost.config
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1,12 +1,138 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "\\\\OZHOST1\\d$\\Documents\\Visual Studio Projects\\SharePrices\\",
|
||||
"Documents": [],
|
||||
"WorkspaceRootPath": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\",
|
||||
"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": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"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": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1,12 +1,135 @@
|
||||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "C:\\Users\\Steve.OZDOMAIN\\source\\repos\\Steves_Code\\Websites\\SharePrices\\",
|
||||
"Documents": [],
|
||||
"WorkspaceRootPath": "C:\\Users\\TSUser\\sources\\repos\\Steves_Code\\Websites\\SharePrices\\",
|
||||
"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": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"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": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Binary file not shown.
@ -25,6 +25,22 @@ Public Class DataAccessLayer
|
||||
DisposeSQLCommand(c)
|
||||
End Function
|
||||
|
||||
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")
|
||||
c.Parameters.AddWithValue("Symbol", Symbol)
|
||||
@ -258,6 +274,7 @@ Public Class DataAccessLayer
|
||||
Select Case dr.GetDataTypeName(fieldNo).ToUpper
|
||||
Case "CHAR", "VARCHAR" : thisRow += """" + dr(fieldNo) + """"
|
||||
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()
|
||||
End Select
|
||||
End If
|
||||
|
@ -40,7 +40,8 @@
|
||||
<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="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="navLog" onclick="showTab(this);" data-div="logDiv">Log</a>
|
||||
</td>
|
||||
@ -73,12 +74,26 @@
|
||||
</div>
|
||||
<div class="tabParent">
|
||||
<div class="tabContainer" id="holdingsDiv">
|
||||
<!-- Old holdings table
|
||||
<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 id="holdingsTableDiv">Holdings table</div>
|
||||
<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>
|
||||
<!-- Old pie charts
|
||||
<br />
|
||||
<table>
|
||||
<tr>
|
||||
@ -91,6 +106,7 @@
|
||||
<td>Current Value per Account<div id="divAccountValue" class="HoldingCurrenciesChart"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
!-->
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabParent">
|
||||
@ -101,9 +117,14 @@
|
||||
<div id="accountsSummaryDiv"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabParent">
|
||||
<div class="tabContainer" id="ledgerDiv">Analysis</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="tabParent">
|
||||
<div class="tabContainer" id="analDiv">Analysis</div>
|
||||
</div>
|
||||
!-->
|
||||
<div class="tabParent">
|
||||
<div class="tabContainer" id="histDiv" style="height: 85%;">History Chart</div>
|
||||
<!--<span onclick="refreshHistoryChart();">Refresh Chart</span>!-->
|
||||
@ -141,6 +162,7 @@
|
||||
<div id="chartTooltip" class="chart-tooltip"></div>
|
||||
<script>
|
||||
let importedFunctions = {};
|
||||
|
||||
function logInfo(msg) {
|
||||
console.info(msg);
|
||||
if (typeof msg == 'object') {
|
||||
@ -202,6 +224,10 @@
|
||||
break;
|
||||
case 'hideEmptyAccounts':
|
||||
break;
|
||||
case 'showSubtotals':
|
||||
break;
|
||||
case 'showCryptoHoldings':
|
||||
break;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -209,7 +235,6 @@
|
||||
import {
|
||||
addInstrument,
|
||||
createSharesTable,
|
||||
createSharesTableRow,
|
||||
getInstruments,
|
||||
redrawAllSharesCharts,
|
||||
refreshHistoryChart,
|
||||
@ -220,10 +245,12 @@
|
||||
showModalDialog_FullScreenChart,
|
||||
showModalDialog_SoldHolding
|
||||
} from "./scripts/SharePrices.js";
|
||||
|
||||
import { updateLedgerTable } from "./scripts/SharePrices_Ledger.js";
|
||||
|
||||
importedFunctions = {
|
||||
addInstrument: addInstrument,
|
||||
createSharesTable: createSharesTable,
|
||||
createSharesTableRow: createSharesTableRow,
|
||||
getInstruments: getInstruments,
|
||||
redrawAllSharesCharts: redrawAllSharesCharts,
|
||||
refreshHistoryChart: refreshHistoryChart,
|
||||
@ -232,7 +259,8 @@
|
||||
showModalDialog_AddInstrument: showModalDialog_AddInstrument,
|
||||
showModalDialog_AddHolding: showModalDialog_AddHolding,
|
||||
showModalDialog_FullScreenChart: showModalDialog_FullScreenChart,
|
||||
showModalDialog_SoldHolding: showModalDialog_SoldHolding
|
||||
showModalDialog_SoldHolding: showModalDialog_SoldHolding,
|
||||
updateLedgerTable: updateLedgerTable
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
@ -258,7 +286,13 @@
|
||||
$("#groupBySymbol").prop('checked', (c == 'true') ? true : false);
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -117,6 +117,16 @@ Public Class SharePrices
|
||||
SetResponseAndCompleteRequest(HttpContext.Current, "application/json", responseText)
|
||||
End Sub
|
||||
|
||||
<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)
|
||||
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)
|
||||
|
||||
'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-Language", "en-GB,en;q=0.5")
|
||||
'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-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)
|
||||
End Function
|
||||
<WebMethod()>
|
||||
@ -355,20 +370,21 @@ Public Class SharePrices
|
||||
Public Shared Sub SearchYahooFinanceShares(SearchString As String)
|
||||
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("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-Encoding", "gzip, deflate, br")
|
||||
'Connection: keep -alive
|
||||
webClient.Headers.Add("Upgrade-Insecure-Requests", "1")
|
||||
webClient.Headers.Add("Sec-Fetch-Dest", "document()")
|
||||
webClient.Headers.Add("Sec-Fetch-Mode", "navigate()")
|
||||
webClient.Headers.Add("Sec-Fetch-Site", "none()")
|
||||
webClient.Headers.Add("Sec-Fetch-User", "?1")
|
||||
'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-Language", "en-GB,en;q=0.5")
|
||||
''webClient.Headers.Add("Accept-Encoding", "gzip, deflate, br")
|
||||
''Connection: keep -alive
|
||||
'webClient.Headers.Add("Upgrade-Insecure-Requests", "1")
|
||||
'webClient.Headers.Add("Sec-Fetch-Dest", "document()")
|
||||
'webClient.Headers.Add("Sec-Fetch-Mode", "navigate()")
|
||||
'webClient.Headers.Add("Sec-Fetch-Site", "none()")
|
||||
'webClient.Headers.Add("Sec-Fetch-User", "?1")
|
||||
|
||||
Dim responseText As String = webClient.DownloadString("https://query1.finance.yahoo.com/v1/finance/search?q=" + SearchString + ""esCount=6&newsCount=0&enableFuzzyQuery=false"esQueryId=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 + ""esCount=6&newsCount=0&enableFuzzyQuery=false"esQueryId=tss_match_phrase_query&multiQuoteQueryId=multi_quote_single_token_query&newsQueryId=news_ss_symbols&enableCb=false&enableNavLinks=false&vespaNewsTimeoutMs=600")
|
||||
Dim responseText As String = DownloadYahooFinanceWebString("https://query1.finance.yahoo.com/v1/finance/search?q=" + SearchString + ""esCount=6&newsCount=0&enableFuzzyQuery=false"esQueryId=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
|
||||
|
||||
@ -390,6 +406,31 @@ 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -260,8 +260,10 @@
|
||||
<Content Include="scripts\jquery\jquery.marquee.min.js" />
|
||||
<Content Include="scripts\js.cookie-2.2.1.min.js" />
|
||||
<Content Include="scripts\SharePrices.js" />
|
||||
<Content Include="scripts\SharePrices_Accounts.js" />
|
||||
<Content Include="scripts\SharePrices_Charts.js" />
|
||||
<Content Include="scripts\SharePrices_Holdings.js" />
|
||||
<Content Include="scripts\SharePrices_Ledger.js" />
|
||||
<Content Include="scripts\tablesorter\dragtable.mod.css" />
|
||||
<Content Include="scripts\tablesorter\filter.formatter.css" />
|
||||
<Content Include="scripts\tablesorter\highlights.css" />
|
||||
|
@ -39,6 +39,11 @@ td {vertical-align: top;}
|
||||
#spnCurrencies a { 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:visited { color: #9a34b7; }
|
||||
|
||||
@ -47,20 +52,49 @@ a:visited { color: #9a34b7; }
|
||||
.miniHoldings th { font-size: x-small; border: 1px solid #505050; }
|
||||
.soldHolding { text-decoration: line-through; }
|
||||
|
||||
/*tr.highlighted, td.highlighted { background-color: gold; }*/
|
||||
.highlighted { background-color: gold; }
|
||||
|
||||
.mainHoldings { font-size: small; }
|
||||
table.mainHoldings { width: 100%; }
|
||||
table.mainHoldings th { background-color: #101040; }
|
||||
table.mainHoldings th, table.mainHoldings td { padding-left: 5px; padding-right: 5px; }
|
||||
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 th, table.watchlist td { padding-left: 5px; padding-right: 5px; }
|
||||
table.watchlist tr:hover { background-color: #404090; }
|
||||
|
||||
.accounts { font-size: small; }
|
||||
.accounts { font-size: 9pt; }
|
||||
/*table.accounts { width: 100%; }*/
|
||||
table.accounts th, table.accounts td { padding-left: 5px; padding-right: 5px; }
|
||||
table.accounts tr:hover { background-color: #404090; }
|
||||
@ -137,8 +171,6 @@ td.no-border { border: 0px; text-align: right; }
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.deletebutton { color: red; 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 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%; }
|
||||
|
||||
*/
|
@ -1,12 +1,12 @@
|
||||
// @ts-check
|
||||
//Testing gitea.copeland-bowen.com #3
|
||||
|
||||
import {formatAmount, generateAxisBreaks, getProfitOrLoss, timespans} from "./SharePrices_Common.js";
|
||||
import {createLongChart, createMidChart, createShortChart, createSingleDayChart, createChart_Flot,
|
||||
createChart, createFullScreenChart, createFullScreenChart_Flot, createFullScreenComparisonChart,
|
||||
createFullScreenComparisonChart_Flot
|
||||
} from "./SharePrices_Charts.js";
|
||||
import {createHoldingsTable} from "./SharePrices_Holdings.js";
|
||||
import { updateHoldingsTables } from "./SharePrices_Holdings.js";
|
||||
import { createAccountsTables } from "./SharePrices_Accounts.js";
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -26,14 +26,43 @@ var vars = {
|
||||
previousDay: 0,
|
||||
previousClose: 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 lastSuccessfulFetch;
|
||||
var currencyFormatter = new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' });
|
||||
var instrumentSearchResults = [];
|
||||
var tablesUpdateTimings = { lastUpdate: 0, timeBetweenUpdates: 10000, timer: 0, updateNeeded: true };
|
||||
var tablesUpdateTimings = { lastUpdate: 0, timeBetweenUpdates: 15000, timer: 0, updateNeeded: true };
|
||||
var indexMarquee = {
|
||||
newContent: '',
|
||||
currentContent: '',
|
||||
@ -127,7 +156,7 @@ var Instruments = {
|
||||
let lastFetchedDate = this.Data[0].lastFetchedIntraday;
|
||||
let lastFetchedIndex = 0;
|
||||
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 = new Date().getTime() - vars.fetchTiming.fetchIntervalIntraday + (2 * timespans.oneMinute) };
|
||||
if (lastFetchedDate > this.Data[i].lastFetchedIntraday) {
|
||||
@ -247,6 +276,14 @@ Date.prototype.yyyymmddhhmmss = function () {
|
||||
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]);
|
||||
};
|
||||
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 () {
|
||||
var yyyy = this.getFullYear().toString();
|
||||
var mm = (this.getMonth() + 1).toString(); // getMonth() is zero-based
|
||||
@ -289,7 +326,11 @@ Number.prototype.autoScale = function () {
|
||||
return this.toFixed(1);
|
||||
} else {
|
||||
if (a < 0.001) {
|
||||
if (a == 0) {
|
||||
return '0';
|
||||
} else {
|
||||
return this.toExponential(2);
|
||||
}
|
||||
} else {
|
||||
return this.toFixed(2);
|
||||
}
|
||||
@ -383,7 +424,7 @@ export function createSharesTable() {
|
||||
logError({ MSG: "Error in createSharesTable", err: err });
|
||||
}
|
||||
};
|
||||
export function createSharesTableRow(instrument) {
|
||||
function createSharesTableRow(instrument) {
|
||||
function getHoldingsTable(Instrument) {
|
||||
if (Instrument.Holdings.length > 0) {
|
||||
let totalUnits = 0;
|
||||
@ -769,7 +810,7 @@ function getYahooDailyData(Instrument) {
|
||||
createLongChart(Instrument);
|
||||
} else {
|
||||
//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) {
|
||||
@ -829,14 +870,14 @@ function getYahooIntradayData(Instrument) {
|
||||
createMidChart(Instrument);
|
||||
createShortChart(Instrument);
|
||||
} else {
|
||||
console.info("No NEW data received for symbol: " + Instrument.Symbol);
|
||||
console.info("getYahooIntradayData - No NEW data received for symbol: " + Instrument.Symbol);
|
||||
}
|
||||
} else {
|
||||
//logWarning({ MSG: "No timestamp series received for symbol: " + Instrument.Symbol, response: response });
|
||||
}
|
||||
} else {
|
||||
//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) {
|
||||
@ -859,10 +900,15 @@ function getYahooSingleDayData(Instrument) {
|
||||
success: function (response) {
|
||||
vars.fetchTiming.lastFetchDuration = (new Date().getTime()) - vars.fetchTiming.lastFetchStartTime;
|
||||
let newData = [];
|
||||
let dbUpdateNeeded = false;
|
||||
|
||||
if (response.chart && response.chart.result) {
|
||||
let dataSeries = response.chart.result[0];
|
||||
|
||||
if (dataSeries.meta) {
|
||||
if (Instrument.CurrentPrice != dataSeries.meta.regularMarketPrice) {
|
||||
dbUpdateNeeded = true;
|
||||
}
|
||||
Instrument.SingleDayPreviousClose = dataSeries.meta.previousClose;
|
||||
Instrument.SingleDayStartDate = dataSeries.meta.currentTradingPeriod.regular.start * 1000;
|
||||
Instrument.SingleDayEndDate = dataSeries.meta.currentTradingPeriod.regular.end * 1000;
|
||||
@ -908,12 +954,26 @@ function getYahooSingleDayData(Instrument) {
|
||||
} else {
|
||||
//console.warn("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 {
|
||||
//console.info("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) {
|
||||
@ -1014,6 +1074,34 @@ function submitNewDailyData(Instrument, NewData) {
|
||||
}
|
||||
function submitNewIntradayData(Instrument, NewData) {
|
||||
//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({
|
||||
type: "POST",
|
||||
contentType: "application/json",
|
||||
@ -1026,6 +1114,7 @@ function submitNewIntradayData(Instrument, NewData) {
|
||||
},
|
||||
failure: function (response) { console.error("SubmitIntradayData error: " + JSON.stringify(response)); }
|
||||
});
|
||||
*/
|
||||
|
||||
//Add new data to Instrument
|
||||
let currentSummary = {};
|
||||
@ -1050,207 +1139,20 @@ function submitNewIntradayData(Instrument, NewData) {
|
||||
}
|
||||
|
||||
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()) {
|
||||
tablesUpdateTimings.lastUpdate = new Date().getTime();
|
||||
|
||||
createHoldingsTable(Instruments, vars);
|
||||
createAccountsTables();
|
||||
//createHoldingsTable(Instruments, vars);
|
||||
createAccountsTables(Instruments);
|
||||
createAnalysisTable();
|
||||
createIndexMarquee();
|
||||
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"> </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"> </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"> </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 getHighestPriceBeforeDate(Instrument, maxDT) {
|
||||
if (Instrument.DailyData) {
|
||||
@ -1465,15 +1367,16 @@ function createIndexMarquee() {
|
||||
//if (i.InstrumentType == 'INDEX' || i.InstrumentType == 'FUTURE') {
|
||||
if (i.ShowInMarquee == 'A') {
|
||||
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) {
|
||||
let percentChange = ((i.CurrentPrice / i.SingleDayPreviousClose) - 1) * 100;
|
||||
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 {
|
||||
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 {
|
||||
t.push('<font class="' + openOrClosed + '">' + i.DisplayName + '<br/>' + i.CurrentPrice + '</font>');
|
||||
t.push('<font class="' + openOrClosed + '">' + label + '<br/>' + i.CurrentPrice + '</font>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
384
Websites/SharePrices/SharePrices/scripts/SharePrices_Accounts.js
Normal file
384
Websites/SharePrices/SharePrices/scripts/SharePrices_Accounts.js
Normal 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"> </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"> </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"> </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"> </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"> </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"> </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);
|
||||
}
|
@ -85,3 +85,12 @@ export function generateAxisBreaks(data, maxGapSize, breakSize) {
|
||||
}
|
||||
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;"> </div>' +
|
||||
'<div class="pcLabel" style="width:' + cellWidth + 'px">' + labelText + '</div>' +
|
||||
'</td>';
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
import { formatAmount } from "./SharePrices_Common.js";
|
||||
|
||||
import { formatAmount, getPercentCell } from "./SharePrices_Common.js";
|
||||
/*
|
||||
export function createHoldingsTable(Instruments, vars) {
|
||||
function getHoldings() {
|
||||
function aggregateHoldings(i) {
|
||||
@ -302,12 +302,17 @@ export function createHoldingsTable(Instruments, vars) {
|
||||
$('#holdingsTableDiv').html(tbl);
|
||||
|
||||
$("#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) {
|
||||
// Prints the current sort order to the console
|
||||
if (event.target.config.sortList.length > 3) {
|
||||
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' });
|
||||
});
|
||||
}
|
||||
@ -354,14 +359,16 @@ export function createHoldingsTable(Instruments, vars) {
|
||||
//$("#" + rowID).addClass("highlighted");
|
||||
}
|
||||
}
|
||||
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;"> </div>' +
|
||||
'<div class="pcLabel" style="width:' + cellWidth + 'px">' + labelText + '</div>' +
|
||||
'</td>';
|
||||
}
|
||||
|
||||
//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;"> </div>' +
|
||||
// '<div class="pcLabel" style="width:' + cellWidth + 'px">' + labelText + '</div>' +
|
||||
// '</td>';
|
||||
//}
|
||||
|
||||
function profitOrLoss(value) {
|
||||
return value >= 0 ? "profit" : "loss";
|
||||
}
|
||||
@ -495,35 +502,6 @@ export function createHoldingsTable(Instruments, vars) {
|
||||
var resort = true;
|
||||
$("#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: </span>' + '<span style="font-size: large">' + formattedAmount + '</span> ';
|
||||
holdingsHTML += '<span style="font-size: small;"><span class="' + (vars.previousClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousClose, "GBP", 0) + '</span> (d)';
|
||||
holdingsHTML += ' / <span class="' + (vars.previousWeekClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousWeekClose, "GBP", 0) + '</span> (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
|
||||
function labelFormatter(label, series) {
|
||||
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;
|
||||
}
|
||||
*/
|
||||
|
||||
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() + '"> </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"> ' + dt + '</td></tr>\n' + //Spacer row
|
||||
let rowsDef = '<tr id="' + subtableID + '_Summary" class="holdingsSubtotalRow"><td> </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's<br/>Gain £</th>' +
|
||||
'<th>Today'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>' + ' ' + '</td>' + //Allocation
|
||||
getPercentCell('#280ea6' /*'#3f2d95'*/, 70, scaledAllocation, allocationPercent.toFixed(1) + '%') + //Allocation
|
||||
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainGBP == 0) ? ' ' : formatAmount(todaysGainGBP, 'GBP', 0)) + '</td>' + //Today's Gain £
|
||||
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainPct == 0) ? ' ' : 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> </td>' +
|
||||
'<td class="num ' + (todaysGain < 0 ? 'loss' : 'profit') + '">' + (todaysGain == 0 ? ' ' : formatAmount(todaysGain, 'GBP', 0)) + '</td>' +
|
||||
'<td> </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> </td>' +
|
||||
'<td class="num ' + (todaysGain < 0 ? 'loss' : 'profit') + '">' + (todaysGain == 0 ? ' ' : formatAmount(todaysGain, 'GBP', 0)) + '</td>' +
|
||||
'<td> </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> </td>' +
|
||||
'<td class="num">' + formatAmount(totalCashGBP, 'GBP', 0) + '</td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </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> </td>' +
|
||||
'<td class="num">' + formatAmount(grandTotalGBP, 'GBP', 0) + '</td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </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: </span>' + '<span style="font-size: large">' + formattedAmount + '</span> ';
|
||||
holdingsHTML += '<span style="font-size: small;"><span class="' + (vars.previousClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousClose, "GBP", 0) + '</span> (d)';
|
||||
holdingsHTML += ' / <span class="' + (vars.previousWeekClose < totalValueGBP ? 'profit">+' : 'loss">') + formatAmount(totalValueGBP - vars.previousWeekClose, "GBP", 0) + '</span> (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() + '"> </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's<br/>Gain £</th>' +
|
||||
'<th>Today'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>' + ' ' + '</td>' + //Allocation
|
||||
getPercentCell('#280ea6' /*'#3f2d95'*/, 70, scaledAllocation, allocationPercent.toFixed(1) + '%') + //Allocation
|
||||
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainGBP == 0) ? ' ' : formatAmount(todaysGainGBP, 'GBP', 0)) + '</td>' + //Today's Gain £
|
||||
'<td class="num ' + todaysProfitOrLoss + '">' + ((todaysGainPct == 0) ? ' ' : 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> </td>' +
|
||||
'<td class="num ' + (todaysGain < 0 ? 'loss' : 'profit') + '">' + (todaysGain == 0 ? ' ' : formatAmount(todaysGain, 'GBP', 0)) + '</td>' +
|
||||
'<td> </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> </td>' +
|
||||
'<td class="num">' + formatAmount(totalCashGBP, 'GBP', 0) + '</td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </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> </td>' +
|
||||
'<td class="num">' + formatAmount(grandTotalGBP, 'GBP', 0) + '</td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </td>' +
|
||||
'<td> </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's Gain</th>' +
|
||||
'<th>Today'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);
|
||||
}
|
117
Websites/SharePrices/SharePrices/scripts/SharePrices_Ledger.js
Normal file
117
Websites/SharePrices/SharePrices/scripts/SharePrices_Ledger.js
Normal 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']
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user