From 3552246c8d1b6eb5fd5678fe969449cac28a6641 Mon Sep 17 00:00:00 2001 From: Steve Date: Sun, 5 Jan 2025 18:30:06 +0000 Subject: [PATCH] 2022-09-24 v2 pre-TypeScript --- Websites/SharePrices/.vs/SharePrices/v17/.suo | Bin 48640 -> 58368 bytes Websites/SharePrices/SharePrices.v12.suo | Bin 69120 -> 69120 bytes .../SharePrices/CreateDBSchema.sql | 62 ++++++++- .../SharePrices/scripts/SharePrices.js | 128 ++++++++++-------- 4 files changed, 136 insertions(+), 54 deletions(-) diff --git a/Websites/SharePrices/.vs/SharePrices/v17/.suo b/Websites/SharePrices/.vs/SharePrices/v17/.suo index b6ea76015d8149a0b5feed225bde5dec164522d2..029dbbf7d6c7dd928e412c418181fefe22677c86 100644 GIT binary patch delta 3768 zcmdT{ZA_cj6@KrFF~%{(fNczzk2r*+smshqAf===7z&9knQU zv}J!L?X@26x#ym9?z!ij`$70yIsAFjO~0Jlw^%VZ-TPlirLr1uy{yU_FonuuOWa%|`nKU;|j+ zfi?{wzs_;7PZu%j%FO7p3V*pV`gsk{2)Y#b0pJFEueM- zdw^EJ2ebiufp(w+*avh1UBI)zGe7~bA9xPv0ltIPUbKBcKX4E@1PlO!z+vDB@I!!C zG=%mAUZ5YuQQ#PG92f?y7u%kS$o~H>@F^EUSt)p^e;?YN4%u?pt7_+ERuP{ z+i@Ov$t@e`c1G>ICGa5kj6v3DQXq5D#MQvtG;WR$o2>H@`;xHI9eYS*QZOf^=YoDR zh5l(B69x*}+6`MZDzs$#f_|B`BVzZGH}?arqHxijypTwvpd%FN)X}KZPUidpVN`I=bs@p@t;464*E? z&sGVMOrrWbQAf*#zcR7kGYU|eA`@#r>0WBcFYz{9CHpqJodCy z*YR)}@-D9xfW}GPY>Pa<>$XsXxLsp98ad_O?o?Tk_udx~M}V{9TggfrvO>YO^Yfiy zK?_}W@>Ds=yh%?B2Xu71t9G_ipI_10?&D?Fd)s~WR~zS^cK)sDwY^&}4BVQB;>>yY%-p6QtlU;a@HX(bA^5~Wg5I)USQMB245^MI_q={T$n z;mD6$9K;bHz(LjzE!GR*Zz&{BU_L(2qaS-3|CmmvuMXv>eTJK3SADw|Yw)TZ-9E3k zg@!vV)X`&48NkJWpT<>tMtu4POmz^h9-*18yp&N~AAae8R?_-_B%EF)k+YUW5}Y$p zTTf1i-E9E8xD)qCPfI(cCTWM{1TQu-Xcu~oQax@*9(znG1E&M`W*xK|6P#Y$t}lZB zB7!!k+VHAD4j@EFRVzNJ1v(v=r4`z{S;h>;F{pTP9q)sXM4~f`be+W^j$bWMiS6XZ zlvS9t67A#akLf7CTIEOS?Hc;=1YH5ixO_#-4$Cv*{Bm_sQJdu$k!Yiw4L{5&P4z81 zaaNKTu2y~GJ|7rONCk(sA8oWQ`lV4&TxIM#%N3z*#&viEkAXu#KkAJurvm{xk*KF( zRc}D$vFtHWBj2;cS4^|(Ax)_+(C;=|70bZaX}G=E7o6afKbieV9cJbVJ_ zcNi;K?K$2QEKQ%iXWLk+7Q+d3^0j=!$*jtnU(HSB66k{UgCwqGWvsTjAu6|Rue#FX zD2@?Cg(LBwWB()CrKsiAv8_|R9f7~Ri372<#w(o?bfT zpuN{_(Y3H$_*FCChV0aLeS}SjFgS>5L7V|vDr zh5mHGqUqJVW*51tO&*)NVo2DH&IGPT+W3~n@sqI$t_h23z!5gn*>^0O-r_rE@=Y6r zJu&W?Gp~%VP_#Jrma=PBCnJBqp{n;YsbE6StEcYiD2=s~ekMx4_r6mdKNyqa)gDuw z`Fi3)65iXie!@z|(?-=o7;lx&-$++AmMQBKaptIw8eSN~J#WJU!A!SG^mOJ&wtoR#z%&K` delta 1702 zcmcIk|7%-S6wkSRP1EExdtJUX?YcJ2LSnNnOJ`QMS~aCph7_Bvb!5}2(XObJQQJg< zI+Kl|!!! z`c69c6KuspuHHSgd6*C<>?I5k9wE319N;x%Yw^&W=O`Vz4279(t(cxy#q@u^yXky> z3x%#3aXVX7Bfw?I2Qy>$qhgo9jy-l)BNL$Tj&yR6ugA~sAi0geMdYh9!`%cw0SopR zC%{kb=cFVn5{@9O7t>)}a4h|QsWYl_(8e9ev|y_z2z{7U@~{(Y$_<%s$~QKRTD7$R zjqL6t-`(in<`r-h}tI-K$r_F05_OgA=n|d1%2JeH~i1dkkbw z#8Y4<#F>{RT=kFgF5}xgN;B7_3+oYB4Sv5=mvh}>u=;v zapT>dw>QF9yL`A9m;@Wv0%LN7Y}^iJA}zCHLEz96K72Q1#RI=x!n2_vHC(|;C{c?3 zt7SltQFR`WxMA@8bf1=SE1vZ%8 zS4WUs$F!yNv?xC#1d6U%F6ZHma?;m<+41>OQm9);T7c{Hm!f9eRF}YBsB2Q!Q0a)Z ze53+cc~(LxwTMe;FJ6pWF?LeHfNb+mgD-Ue{SV>cPL}`x diff --git a/Websites/SharePrices/SharePrices.v12.suo b/Websites/SharePrices/SharePrices.v12.suo index cc492c64b5f6208b8bb9ed5f2f173ea8071f9f0c..6d2302ef1b4df577729325f45c2a38bc770c3bff 100644 GIT binary patch delta 6141 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 delta 5267 zcmd^D3s9BE6+XLM5RmuF7l{`HBQHTkrHO@$P{(LMED&uZt<; zG$Dv6;Dd@HxRp#E=+WP1&>wv@!^x2a zokp(`C^%)lw&93Yj?f?fvB0~dfM;A7wy zKr4n~JkQ0;nBlAOCN*>~{ z0G%`@^86+^%KZ*{B%fuGtM~jI7)+=>{$Dav-|9Cmn|ubx9=M!3KVo|6u`s__Xg$um zuTUZU8PO;t@j%dA2cibhSSK7i&@yMDThQN)gq;c95G3{%(A!9EJva3;@&yILI3!k> zOX5X)$QY%dApbWwzo9Q62QdFW9NY-HNw4v5qF%&tBp{r=<3dzA4EY58H%Ad&hYyhk zEJootCbuvv0Y{|_+OEiC4`@w*wUv;2!rE^^y&>A~3c(f=H(89F!lKuCGNB$$fhj zW#~^j)vPzL$``pQFq<6}Ie`k>qjm-+ab@{Pq7IlT9t|^aqdi7DA?LnBbQIHXyiDW> z^Ic=`l!$Ht_Tes~oiq;a;K}nR5?wnJ_PW7SSP4_t}^aedjsY0mS0F z$bvsW{@OyKFA-FlvWO@e^`;hiGz<#SxkPPHU@MSTSYSgQ0tyEjR}tNWqvsW(B8=x6 zVU(Mqvss(SiB{N6(HWhp(_=&?8@n!YMk>lRurdd=R<#y`F!7^xL_0wP3$c?h9kKy? zfSsHN`WAe3+6vQHdhB*o0?_=!kVD`1eau6Q-bOj;iYEFs=sf5boY(X}Xx8+ve?=67 zO!8AYQF0J8uWq96VWBiHMqY#91gMm6K@Lm#)evS`AP2d-7z+%J28GWjM=}b=mCyxx z4*Cz{7>!1Z49Sd&kyHw(lpCjN@~d;T`Rf*H^OcT8%o419KW5Z~-C32%C?69_k&bD& z1PGN2XRYDg|xb&j|ZNe?GuyJDxnVmeF$X zyN@tBh6t_3A#6@Ugg`I8L<%*c^D+!JoPq;TEIZBU9%$EDjsNVN#xMSqS+e-zZAN=x zXz6`M??UgxhuVVkiBnQK(R$F&!-x)os<7*a)R%V2lUwZ0@YeW=K9WbOv=8SN!(&Er zi{bJVZZSM4ja#1NdO9ZsZvlS=%|aSRP2sc?A>Q#rPWiB#o5?8?TUHNx5{}g`;nV{9 z!7@&-W9x!*IrVqOWevIy@{0AGYA|mn63gBb$#W8wpg#tBmvdU^Bn)9`;&4d#UUL;| z7@NSv89q#8Cm4InIw0>%G|^bS#`$-!9gqP3xhR_#B-*);5)KP5LEN&BTZ(6Bl}0yM zX?Qg!WGuZ~!zlw<6m*DVI?22QQezw;p{Yztlb zh|^mLLE=$PE1^H<1Se0g*&@ECQJkKUB2t1n{@Z0k`G#eK=$q97B-X!O44!2zP@bX~ zJj+_3JVh~hmbD=9DT+bQTA&m0$#EztA0fTdkoIAX+;S_we?dDQtD88Xd{V$gjh=7j zR0sY*3n$#gEZs{YQ&X&ldrj*>l|?kDl8iJjTt__UvQk#PD+8 zEx(B5%Y~XfeiJjfKjk~FWun(q%e(bYnJFfrr|}pVkIH7h6gg1}yCgdCdtBrU+xRu1 znv;HrtNKyxtRdx$c9j^zbiMN2;3qztx+k4|EaZ7^>OJpr_Ak83t1Z(;c$ijiRySuY zW0i|^m1}v!(#Zy zRXBrsTvuY-h;T8ZXbH0u6$6rm(NGbzXZWSI=}qh3dyurMVCMXFp|;Zs!FXb-NQ^%& z-1O6)$69LQmYM90SEhL!f2Z!itzE(Il~z?v(c60UtUhGeHo^MFiJ|&;K@>sA4Qrp6h#I&yws! zB0eltz88L5OR^eY6URJSaeg*><1-k??;-x05nGe9gmM2h(NP_0+Hd@)%xjyX@?8T)w=%xn!lVa diff --git a/Websites/SharePrices/SharePrices/CreateDBSchema.sql b/Websites/SharePrices/SharePrices/CreateDBSchema.sql index 0c9fa2d..7ebfc46 100644 --- a/Websites/SharePrices/SharePrices/CreateDBSchema.sql +++ b/Websites/SharePrices/SharePrices/CreateDBSchema.sql @@ -168,6 +168,65 @@ GO GRANT EXECUTE ON TYPE::PriceDataType TO WebApp_Role GO +CREATE FUNCTION dbo.fn_GetExchangeRate(@Currency VARCHAR(3), @DT DATETIME) +RETURNS REAL +AS +BEGIN + DECLARE @Rate REAL + IF @Currency = 'GBp' COLLATE Latin1_General_CS_AS + BEGIN + SET @Rate = 100 + END + ELSE + BEGIN + IF @Currency = 'GBP' COLLATE Latin1_General_CS_AS + BEGIN + SET @Rate = 1 + END + ELSE + BEGIN + DECLARE @InstrumentID INT + SELECT @InstrumentID = InstrumentID FROM Instrument WHERE FullName = 'GBP/' + @Currency + IF @InstrumentID IS NULL + BEGIN + --Currency pair Instrument not found - return zero to indicate error + SET @Rate = 0 + END + ELSE + BEGIN + --Is there a rate for this exact datetime? + SELECT @Rate = ClosePrice FROM InstrumentHistory_Intraday WHERE InstrumentID = @InstrumentID AND HistoryDT = @DT + IF @Rate IS NULL + BEGIN + --No exect match + DECLARE @StartDT DATETIME, @EndDT DATETIME, @StartRate REAL, @EndRate REAL + --@StartID INT, @EndID INT, + SELECT TOP 1 @StartDT = HistoryDT, @StartRate = ClosePrice FROM InstrumentHistory_Intraday WHERE InstrumentID = @InstrumentID AND HistoryDT < @DT ORDER BY HistoryDT DESC + SELECT TOP 1 @EndDT = HistoryDT, @EndRate = OpenPrice FROM InstrumentHistory_Intraday WHERE InstrumentID = @InstrumentID AND HistoryDT > @DT ORDER BY HistoryDT + IF @StartDT IS NOT NULL AND @EndDT IS NOT NULL + BEGIN + --Work out how far between the 2 dates our DT is, and calculate rate accordingly + DECLARE @TotalSeconds BIGINT + DECLARE @Percent REAL + SELECT @TotalSeconds = DATEDIFF(second, @StartDT, @EndDT) + SET @Percent = CONVERT(REAL, DATEDIFF(second, @StartDT, @DT)) / @TotalSeconds * 100 + SET @Rate = @StartRate + ((@EndRate - @StartRate) / 100 * @Percent) + END + ELSE + BEGIN + --We don't have BOTH a start AND end price + --Return the non-NULL rate if we have one, zero otherwise + SET @Rate = COALESCE(@StartRate, @EndRate, 0) + END + END + END + END + END + + RETURN @Rate +END +GO + --CREATE PROCEDURE usp_InsertInstrument (@ExchangeShortName varchar(10), @Symbol varchar(7), @FullName varchar(100)) CREATE PROCEDURE usp_InsertInstrument (@Symbol varchar(8), @FullName varchar(100)) AS @@ -629,7 +688,8 @@ BEGIN h.PurchaseDate, h.NoUnits, h.PurchasePricePerUnit, - h.ActualExchangeRate, + ISNULL(h.ActualExchangeRate, dbo.fn_GetExchangeRate(i.Currency, h.PurchaseDate)) as [PurchaseExchangeRate], + h.NoUnits * h.PurchasePricePerUnit / ISNULL(h.ActualExchangeRate, dbo.fn_GetExchangeRate(i.Currency, h.PurchaseDate)) as [BookCostGBP], h.SoldDate FROM Holding h diff --git a/Websites/SharePrices/SharePrices/scripts/SharePrices.js b/Websites/SharePrices/SharePrices/scripts/SharePrices.js index a1bad47..a4ab09a 100644 --- a/Websites/SharePrices/SharePrices/scripts/SharePrices.js +++ b/Websites/SharePrices/SharePrices/scripts/SharePrices.js @@ -1,4 +1,5 @@ -'use strict'; +// @ts-check +'use strict'; 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 fetchIntervalDaily = 12 * timespans.oneHour; var fetchIntervalIntraday = 4 * timespans.oneHour; @@ -507,6 +508,7 @@ function createSharesTableRow(instrument) { if (Instrument.Holdings.length > 0) { let totalUnits = 0; let totalPrice = 0; + let totalPriceGBP = 0; let noRows = 0; let t = ''; for (let i = 0; i < Instrument.Holdings.length; i++) { @@ -515,6 +517,7 @@ function createSharesTableRow(instrument) { noRows++; totalUnits += h.NoUnits; totalPrice += (h.NoUnits * h.PurchasePricePerUnit); + totalPriceGBP += h.BookCostGBP; t += '' + '' + '' + @@ -537,12 +540,15 @@ function createSharesTableRow(instrument) { if (totalUnits > 0) { Instrument.TotalUnitsHeld = totalUnits; Instrument.TotalHoldingsCost = totalPrice; + Instrument.TotalHoldingsCostGBP = totalPriceGBP; + //Instrument.BreakevenPrice = totalPrice / totalUnits; Instrument.BreakevenPrice = totalPrice / totalUnits; t += '' + '' + '' + //'' + '' + + //'' + '' + ''; } @@ -551,6 +557,7 @@ function createSharesTableRow(instrument) { } else { delete Instrument.TotalUnitsHeld; delete Instrument.TotalHoldingsCost; + delete Instrument.TotalHoldingsCostGBP; delete Instrument.BreakevenPrice; return ''; } @@ -579,6 +586,42 @@ function createSharesTableRow(instrument) { //'' }; +function getCurrentValueContent(Instrument) { + let currentValue = ''; + if (Instrument.CurrentPrice) { + if (Instrument.TotalUnitsHeld > 0) { + currentValue = '
'; + //currentValue += 'Price (' + Instrument.Currency + '): ' + (Instrument.BreakevenPrice < 0.1 ? Instrument.BreakevenPrice.toPrecision(3) : Instrument.BreakevenPrice.toFixed(2)) + ' -> ' + (Instrument.CurrentPrice < 0.1 ? Instrument.CurrentPrice.toPrecision(3) : Instrument.CurrentPrice.toFixed(2)) + ': ' + getProfitOrLoss(Instrument.BreakevenPrice, Instrument.CurrentPrice) + '
'; + currentValue += 'Price (' + Instrument.Currency + '): ' + (Instrument.BreakevenPrice < 0.1 ? Instrument.BreakevenPrice.autoScale() : Instrument.BreakevenPrice.toFixed(2)) + ' -> ' + (Instrument.CurrentPrice < 0.1 ? Instrument.CurrentPrice.autoScale() : Instrument.CurrentPrice.toFixed(2)) + ': ' + getProfitOrLoss(Instrument.BreakevenPrice, Instrument.CurrentPrice) + '
'; + //currentValue += 'Value: ' + (Instrument.TotalHoldingsCost).toFixed(2) + ' -> ' + (Instrument.TotalUnitsHeld * Instrument.CurrentPrice).toFixed(2) + ': ' + getProfitOrLoss(Instrument.TotalHoldingsCost, Instrument.TotalUnitsHeld * Instrument.CurrentPrice); + currentValue += 'Book Cost (GBP): ' + (Instrument.TotalHoldingsCostGBP).toFixed(2); + let exRate = Instruments.GetExchangeRate(Instrument.Currency, 'GBP'); + if (exRate) { + if (Instrument.Currency != 'GBp') { + currentValue += '
GBP/' + Instrument.Currency + ' = ' + exRate.toFixed(4); + } + currentValue += '
'; + //currentValue += 'Current value:
' + currencyFormatter.format(Instrument.TotalUnitsHeld * Instrument.CurrentPrice / exRate) + ': ' + getProfitOrLoss(Instrument.TotalHoldingsCostGBP / exRate, Instrument.TotalUnitsHeld * Instrument.CurrentPrice / exRate, 1); + currentValue += 'Current value:
' + currencyFormatter.format(Instrument.TotalUnitsHeld * Instrument.CurrentPrice / exRate) + ': ' + getProfitOrLoss(Instrument.TotalHoldingsCostGBP, Instrument.TotalUnitsHeld * Instrument.CurrentPrice / exRate, 1); + currentValue += '
'; + } else { + currentValue += '
' + Instrument.Currency; + } + } else { + //INDEX, CURRENCY, EQUITY + if (Instrument.InstrumentType == 'CURRENCY') { + currentValue = 'Exchange Rate: ' + Instrument.CurrentPrice.toFixed(4); + } else { + if (Instrument.InstrumentType == 'CRYPTOCURRENCY' && Math.abs(Instrument.CurrentPrice) < 0.001) { + currentValue = 'Price (' + Instrument.Currency + '): ' + Instrument.CurrentPrice.toExponential(); + } else { + currentValue = 'Price (' + Instrument.Currency + '): ' + Instrument.CurrentPrice.toFixed(2); + } + } + } + } + return currentValue; +} function moveInstrumentUp(symbol) { let i = Instruments.indexOfSymbol(symbol); if (i > 0) { @@ -2341,40 +2384,6 @@ function getYahooIntradayData(Instrument) { failure: function (response) { console.error("getYahooIntradayData error:"); console.info(response); } }); } -function getCurrentValueContent(Instrument) { - let currentValue = ''; - if (Instrument.CurrentPrice) { - if (Instrument.TotalUnitsHeld > 0) { - currentValue = '
'; - //currentValue += 'Price (' + Instrument.Currency + '): ' + (Instrument.BreakevenPrice < 0.1 ? Instrument.BreakevenPrice.toPrecision(3) : Instrument.BreakevenPrice.toFixed(2)) + ' -> ' + (Instrument.CurrentPrice < 0.1 ? Instrument.CurrentPrice.toPrecision(3) : Instrument.CurrentPrice.toFixed(2)) + ': ' + getProfitOrLoss(Instrument.BreakevenPrice, Instrument.CurrentPrice) + '
'; - currentValue += 'Price (' + Instrument.Currency + '): ' + (Instrument.BreakevenPrice < 0.1 ? Instrument.BreakevenPrice.autoScale() : Instrument.BreakevenPrice.toFixed(2)) + ' -> ' + (Instrument.CurrentPrice < 0.1 ? Instrument.CurrentPrice.autoScale() : Instrument.CurrentPrice.toFixed(2)) + ': ' + getProfitOrLoss(Instrument.BreakevenPrice, Instrument.CurrentPrice) + '
'; - currentValue += 'Value: ' + (Instrument.TotalHoldingsCost).toFixed(2) + ' -> ' + (Instrument.TotalUnitsHeld * Instrument.CurrentPrice).toFixed(2) + ': ' + getProfitOrLoss(Instrument.TotalHoldingsCost, Instrument.TotalUnitsHeld * Instrument.CurrentPrice); - let exRate = Instruments.GetExchangeRate(Instrument.Currency, 'GBP'); - if (exRate) { - if (Instrument.Currency != 'GBp') { - currentValue += '
GBP/' + Instrument.Currency + ' = ' + exRate.toFixed(4); - } - currentValue += '
'; - currentValue += 'Current value:
' + currencyFormatter.format(Instrument.TotalUnitsHeld * Instrument.CurrentPrice / exRate) + ': ' + getProfitOrLoss(Instrument.TotalHoldingsCost / exRate, Instrument.TotalUnitsHeld * Instrument.CurrentPrice / exRate, 1); - currentValue += '
'; - } else { - currentValue += '
' + Instrument.Currency; - } - } else { - //INDEX, CURRENCY, EQUITY - if (Instrument.InstrumentType == 'CURRENCY') { - currentValue = 'Exchange Rate: ' + Instrument.CurrentPrice.toFixed(4); - } else { - if (Instrument.InstrumentType == 'CRYPTOCURRENCY' && Math.abs(Instrument.CurrentPrice) < 0.001) { - currentValue = 'Price (' + Instrument.Currency + '): ' + Instrument.CurrentPrice.toExponential(); - } else { - currentValue = 'Price (' + Instrument.Currency + '): ' + Instrument.CurrentPrice.toFixed(2); - } - } - } - } - return currentValue; -} function getYahooSingleDayData(Instrument) { //console.info('getYahooSingleDayData: ' + Instrument.Symbol); Instrument.lastFetchedSingleDay = new Date().getTime(); @@ -2966,8 +2975,10 @@ function createHoldingsTable() { if (h.SoldDate == null) { aggUnits += h.NoUnits; aggBookCost += h.NoUnits * h.PurchasePricePerUnit; - aggBookCostGBP += h.NoUnits * h.PurchasePricePerUnit / exchangeRate; - bookCostPerAccount.addCategoryAmount(h.AccountName, (h.NoUnits * h.PurchasePricePerUnit) / exchangeRate); + //aggBookCostGBP += h.NoUnits * h.PurchasePricePerUnit / exchangeRate; + aggBookCostGBP += h.BookCostGBP; + //bookCostPerAccount.addCategoryAmount(h.AccountName, (h.NoUnits * h.PurchasePricePerUnit) / exchangeRate); + bookCostPerAccount.addCategoryAmount(h.AccountName, h.BookCostGBP); if (h.PurchaseDate < minPurchaseData) { minPurchaseData = h.PurchaseDate; } if (h.PurchaseDate > maxPurchaseDate) { maxPurchaseDate = h.PurchaseDate; } @@ -2990,7 +3001,8 @@ function createHoldingsTable() { aggCurrentValue = aggUnits * (i.Currency == 'GBp' ? i.CurrentPrice / 100 : i.CurrentPrice); if (exchangeRate) { aggCurrentValueGBP = (aggUnits * i.CurrentPrice) / exchangeRate; - aggGainGBP = ((i.CurrentPrice - aggPurchasePricePerUnit) * aggUnits) / exchangeRate; + //aggGainGBP = ((i.CurrentPrice - aggPurchasePricePerUnit) * aggUnits) / exchangeRate; + aggGainGBP = aggCurrentValueGBP - aggBookCostGBP; aggSingleDayGainPercent = ((i.CurrentPrice / i.SingleDayPreviousClose) - 1) * 100; aggSingleDayProfitOrLoss = aggSingleDayGainGBP < 0 ? 'loss' : 'profit'; } @@ -3013,7 +3025,8 @@ function createHoldingsTable() { bookCostGBP: aggBookCostGBP, currentValue: aggCurrentValue, gain: (i.Currency == 'GBp' ? (i.CurrentPrice - aggPurchasePricePerUnit) / 100 : (i.CurrentPrice - aggPurchasePricePerUnit)) * aggUnits, - gainPercent: (i.CurrentPrice - aggPurchasePricePerUnit) / aggPurchasePricePerUnit * 100, + //gainPercent: (i.CurrentPrice - aggPurchasePricePerUnit) / aggPurchasePricePerUnit * 100, + gainPercent: aggGainGBP / aggBookCostGBP * 100, currentValueGBP: aggCurrentValueGBP, gainGBP: aggGainGBP, singleDayGainGBP: aggSingleDayGainGBP, @@ -3087,10 +3100,12 @@ function createHoldingsTable() { if (agg.noUnits > 0) { r.push(agg); - holdingCurrencies.addHoldingCurrency(i.Currency, agg.noUnits * agg.purchasePricePerUnit); + //holdingCurrencies.addHoldingCurrency(i.Currency, agg.noUnits * agg.purchasePricePerUnit); + holdingCurrencies.addHoldingCurrency(i.Currency.toUpperCase(), agg.noUnits * agg.purchasePricePerUnit / (i.Currency == "GBp" ? 100 : 1)); if (i.CurrentPrice) { if (agg.currentValueGBP > maxCurrentValueGBP) { maxCurrentValueGBP = agg.currentValueGBP }; - holdingCurrenciesCurrentValue.addHoldingCurrency(i.Currency, agg.noUnits * i.CurrentPrice); + //holdingCurrenciesCurrentValue.addHoldingCurrency(i.Currency, agg.noUnits * i.CurrentPrice); + holdingCurrenciesCurrentValue.addHoldingCurrency(i.Currency.toUpperCase(), agg.noUnits * i.CurrentPrice / (i.Currency == "GBp" ? 100 : 1)); if (agg.currentExchangeRate) { totalBookCostGBP += agg.bookCostGBP; totalValueGBP += agg.currentValueGBP; @@ -3107,7 +3122,7 @@ function createHoldingsTable() { let h = i.Holdings[hn]; if (h.SoldDate == null) { let holdingBookCost = h.NoUnits * h.PurchasePricePerUnit; - + let currentHoldingValue = h.NoUnits * (i.Currency == 'GBp' ? i.CurrentPrice / 100 : i.CurrentPrice); let holdingCurrentValueGBP = 0, @@ -3120,7 +3135,8 @@ function createHoldingsTable() { if (exchangeRate) { let holdingCurrentValueGBP = (h.NoUnits * i.CurrentPrice) / exchangeRate; - let holdingGainGBP = ((i.CurrentPrice - h.PurchasePricePerUnit) * h.NoUnits) / exchangeRate; + //let holdingGainGBP = ((i.CurrentPrice - h.PurchasePricePerUnit) * h.NoUnits) / exchangeRate; + let holdingGainGBP = holdingCurrentValueGBP - h.BookCostGBP; let singleDayGainGBP = ((i.CurrentPrice - (h.PurchaseDate > i.SingleDayStartDate ? h.PurchasePricePerUnit : i.SingleDayPreviousClose)) * h.NoUnits) / exchangeRate; let singleDayGainPercent = ((i.CurrentPrice / i.SingleDayPreviousClose) - 1) * 100; @@ -3145,7 +3161,8 @@ function createHoldingsTable() { bookCost: holdingBookCost, currentValue: currentHoldingValue, gain: (i.Currency == 'GBp' ? (i.CurrentPrice - h.PurchasePricePerUnit) / 100 : (i.CurrentPrice - h.PurchasePricePerUnit)) * h.NoUnits, - gainPercent: (i.CurrentPrice - h.PurchasePricePerUnit) / h.PurchasePricePerUnit * 100, + //gainPercent: (i.CurrentPrice - h.PurchasePricePerUnit) / h.PurchasePricePerUnit * 100, + gainPercent: holdingGainGBP / h.BookCostGBP * 100, currentValueGBP: holdingCurrentValueGBP, gainGBP: holdingGainGBP, singleDayGainGBP: singleDayGainGBP, @@ -3163,7 +3180,8 @@ function createHoldingsTable() { currentValuePerAccount.addCategoryAmount(h.AccountName, holdingCurrentValueGBP); bookCostPerAccount.addCategoryAmount(h.AccountName, holdingBookCost / exchangeRate); - totalBookCostGBP += holdingBookCost / exchangeRate; + //totalBookCostGBP += holdingBookCost / exchangeRate; + totalBookCostGBP += holdingBookCostGBP; totalValueGBP += holdingCurrentValueGBP; totalGainGBP += holdingGainGBP; todaysGainGBP += (marketIsOpen == 0 ? 0 : singleDayGainGBP); @@ -3401,19 +3419,21 @@ function createAccountsTables() { noUnits: holding.NoUnits, cost: holding.NoUnits * holding.PurchasePricePerUnit } - if (exchangeRate) { - h.costGBP = h.cost / exchangeRate; - a.totalCostGBP += h.costGBP; - } + //if (exchangeRate) { + //h.costGBP = h.cost / exchangeRate; + h.costGBP = holding.BookCostGBP; + 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; - a.totalValueGBP += h.currentValueGBP; + //h.gainGBP = h.gain / exchangeRate; + h.gainGBP = h.currentValueGBP - h.costGBP; a.totalGainGBP += h.gainGBP; + a.totalValueGBP += h.currentValueGBP; } } a.holdings.push(h); @@ -3487,6 +3507,7 @@ function createAccountsTables() { let h = a.holdings[hx]; accountAltRow = !accountAltRow; let holdingProfitOrLoss = h.gain < 0 ? 'loss' : 'profit'; + let holdingGBPProfitOrLoss = h.gainGBP < 0 ? 'loss' : 'profit'; accountsTables += '' + '' + '' + @@ -3499,8 +3520,9 @@ function createAccountsTables() { '' + '' + '' + - '' + - '' + + '' + + //'' + + '' + ''; } accountsTables += '
AccountBuy DatePriceUnitsTotal
×' + h.AccountName + '' + new Date(h.PurchaseDate).yyyymmdd() + '' + formatAmount(h.PurchasePricePerUnit, '', 2) + '
Total' + formatAmount(Instrument.BreakevenPrice, '', 2) + '' + formatAmount(Instrument.TotalUnitsHeld, '', 0) + '' + Instrument.TotalUnitsHeld.autoScale() + '' + formatAmount(Instrument.TotalHoldingsCost, '', 0) + '' + formatAmount(Instrument.TotalHoldingsCost, '', 0) + '
' + h.instrumentName + '' + h.symbol + '' + (h.currency == 'GBp' ? formatAmount(h.currentValue / 100, 'GBP', 2) : formatAmount(h.currentValue, h.currency, 2)) + '' + formatAmount(h.currentValueGBP, 'GBP', 2) + '' + formatAmount(h.gain, h.currency, 2) + '' + formatAmount(h.gainGBP, 'GBP', 2) + '' + ((h.gain / h.cost) * 100).toFixed(1) + '%' + formatAmount(h.gainGBP, 'GBP', 2) + '' + ((h.gain / h.cost) * 100).toFixed(1) + '%' + ((h.gainGBP / h.costGBP) * 100).toFixed(1) + '%
';