diff --git a/Websites/SharePrices/.vs/SharePrices/v16/.suo b/Websites/SharePrices/.vs/SharePrices/v16/.suo new file mode 100644 index 0000000..df1a7c1 Binary files /dev/null and b/Websites/SharePrices/.vs/SharePrices/v16/.suo differ diff --git a/Websites/SharePrices/.vs/SharePrices/v17/.suo b/Websites/SharePrices/.vs/SharePrices/v17/.suo index 029dbbf..a35604e 100644 Binary files a/Websites/SharePrices/.vs/SharePrices/v17/.suo and b/Websites/SharePrices/.vs/SharePrices/v17/.suo differ diff --git a/Websites/SharePrices/SharePrices.v12.suo b/Websites/SharePrices/SharePrices.v12.suo index 6d2302e..01a0154 100644 Binary files a/Websites/SharePrices/SharePrices.v12.suo and b/Websites/SharePrices/SharePrices.v12.suo differ diff --git a/Websites/SharePrices/SharePrices/App_Code/DataAccessLayer.vb b/Websites/SharePrices/SharePrices/App_Code/DataAccessLayer.vb index fb2a1d7..6394bb4 100644 --- a/Websites/SharePrices/SharePrices/App_Code/DataAccessLayer.vb +++ b/Websites/SharePrices/SharePrices/App_Code/DataAccessLayer.vb @@ -180,14 +180,25 @@ Public Class DataAccessLayer ' DeleteHolding = DataReaderToJSONString(c.ExecuteReader()) ' DisposeSQLCommand(c) 'End Function - Public Shared Function SoldHolding(HoldingID As Integer, SoldDate As DateTime) As String + Public Shared Function SoldHolding(HoldingID As Integer, SoldDate As DateTime, SoldCurrency As String, SoldProceeds As Double) As String Dim c As SqlCommand = GetSQLCommand("usp_SoldHolding") c.Parameters.AddWithValue("HoldingID", HoldingID) c.Parameters.AddWithValue("SoldDate", SoldDate) + c.Parameters.AddWithValue("SoldCurrency", SoldCurrency) + c.Parameters.AddWithValue("SoldProceeds", SoldProceeds) SoldHolding = DataReaderToJSONString(c.ExecuteReader()) DisposeSQLCommand(c) End Function + Public Shared Function SetAccountCashValue(AccountName As String, Currency As String, Value As Double) As String + Dim c As SqlCommand = GetSQLCommand("usp_SetAccountCashValue") + c.Parameters.AddWithValue("AccountName", AccountName) + c.Parameters.AddWithValue("Currency", Currency) + c.Parameters.AddWithValue("Value", Value) + SetAccountCashValue = DataReaderToJSONString(c.ExecuteReader()) + DisposeSQLCommand(c) + End Function + Public Shared Function SwapInstrumentDisplayOrders(Symbol1 As String, Symbol2 As String) As String Dim c As SqlCommand = GetSQLCommand("usp_SwapDisplayOrder") c.Parameters.AddWithValue("Symbol1", Symbol1) @@ -196,6 +207,19 @@ Public Class DataAccessLayer DisposeSQLCommand(c) End Function + Public Shared Function SetTotalHoldingsValues(TotalValue As Double) As String + Dim c As SqlCommand = GetSQLCommand("usp_SetTotalHoldingsValue") + c.Parameters.AddWithValue("TotalValueGBP", TotalValue) + SetTotalHoldingsValues = DataReaderToJSONString(c.ExecuteReader()) + DisposeSQLCommand(c) + End Function + + Public Shared Function GetTotalHoldingsHistory() As String + Dim c As SqlCommand = GetSQLCommand("usp_GetTotalHoldingsHistory") + GetTotalHoldingsHistory = DataReaderToJSONString(c.ExecuteReader()) + DisposeSQLCommand(c) + End Function + Private Shared Function GetSQLConnection() As SqlConnection Dim c As New SqlConnection("Server=OZHOST1\SQL2008;Database=SharePrices;Trusted_Connection=True;Application Name=Share Prices Web;") c.Open() diff --git a/Websites/SharePrices/SharePrices/CreateDBSchema.sql b/Websites/SharePrices/SharePrices/CreateDBSchema.sql index 7ebfc46..bb0e965 100644 --- a/Websites/SharePrices/SharePrices/CreateDBSchema.sql +++ b/Websites/SharePrices/SharePrices/CreateDBSchema.sql @@ -5,6 +5,8 @@ GO DROP VIEW vErroneousPrices_Intraday DROP VIEW vErroneousPrices_Daily DROP VIEW vHolding +DROP FUNCTION dbo.fn_GetExchangeRate +DROP FUNCTION dbo.fn_GetPriceAtDate DROP PROCEDURE usp_SwapDisplayOrder DROP PROCEDURE usp_GetHoldingsHistory --DROP PROCEDURE usp_DeleteHolding @@ -25,6 +27,7 @@ DROP TABLE Account DROP TABLE InstrumentHistory_Daily DROP TABLE InstrumentHistory_Intraday DROP TABLE Instrument +DROP TABLE TotalHoldingsHistory_Daily --DROP TABLE Exchange */ GO @@ -67,6 +70,7 @@ CREATE TABLE Instrument ( CurrentPrice real NULL, InstrumentType VARCHAR(15) NULL, ShowInMarquee CHAR(1) NULL, -- A = Always, O = Only when open, NULL = Never + WatchlistID tinyint NULL, --Not a real ID yet TradeDayStart datetime NULL, TradeDayEnd datetime NULL, LastUpdated datetime NULL, @@ -139,15 +143,31 @@ CREATE TABLE Holding ( AccountID tinyint NOT NULL, InstrumentID smallint NOT NULL, --NoUnits int NOT NULL, - NoUnits real NOT NULL, + --NoUnits real NOT NULL, + NoUnits numeric(36, 12) NOT NULL, --PurchasePricePerUnit money NOT NULL, - PurchasePricePerUnit real NOT NULL, - ActualExchangeRate real NULL, + --PurchasePricePerUnit real NOT NULL, + PurchasePricePerUnit numeric(36, 12) NOT NULL, + --ActualExchangeRate real NULL, + ActualExchangeRate numeric(36, 12) NULL, PurchaseDate datetime NOT NULL, SoldDate datetime NULL, + SoldCurrencyID smallint NULL, + SoldProceeds numeric(36, 12) NULL, CONSTRAINT PK_Holding PRIMARY KEY CLUSTERED (HoldingID), CONSTRAINT FK_Holding_Account FOREIGN KEY (AccountID) REFERENCES Account (AccountID), - CONSTRAINT FK_Holding_Instrument FOREIGN KEY (InstrumentID) REFERENCES Instrument (InstrumentID) + CONSTRAINT FK_Holding_Instrument FOREIGN KEY (InstrumentID) REFERENCES Instrument (InstrumentID), + CONSTRAINT FK_Holding_SoldCurrencyInstrument FOREIGN KEY (SoldCurrencyID) REFERENCES Instrument (InstrumentID) +) +GO + +CREATE TABLE TotalHoldingsHistory_Daily ( + HistoryDate date NOT NULL, + [Open] int NOT NULL, + Low int NOT NULL, + High int NOT NULL, + [Close] int NOT NULL, + CONSTRAINT PK_TotalHoldingsHistory_Daily PRIMARY KEY CLUSTERED (HistoryDate) ) GO @@ -227,6 +247,47 @@ BEGIN END GO +CREATE FUNCTION dbo.fn_GetPriceAtDate(@InstrumentID INT, @DT DATETIME) +RETURNS REAL +AS +BEGIN + DECLARE @Rate REAL + + IF @InstrumentID IS NULL OR @DT IS NULL + BEGIN + RETURN 0.0 + END + + --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 + + 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 @@ -350,29 +411,50 @@ BEGIN SET NOCOUNT ON SELECT - i.DisplayOrder, - --e.ShortName as [Exchange], - i.FullName as [InstrumentName], - ISNULL(i.DisplayName, LEFT(i.FullName, 30)) as [DisplayName], - i.Symbol as [Symbol], - i.PostPandemicDilution as [PostPandemicDilution], - i.GMTOffset as [GMTOffset], - i.Currency as [Currency], - i.CurrentPrice as [CurrentPrice], - i.InstrumentType as [InstrumentType], - i.ShowInMarquee as [ShowInMarquee], - i.TradeDayStart as [SingleDayStartDate], - i.TradeDayEnd as [SingleDayEndDate], - ISNULL((SELECT MIN(dd.HistoryDT) FROM InstrumentHistory_Daily dd WHERE dd.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '2030-12-31')) as [MinDailyDate], - ISNULL((SELECT MAX(dd.HistoryDT) FROM InstrumentHistory_Daily dd WHERE dd.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '1970-01-01')) as [MaxDailyDate], - ISNULL((SELECT MIN(id.HistoryDT) FROM InstrumentHistory_Intraday id WHERE id.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '2030-12-31')) as [MinIntradayDate], - ISNULL((SELECT MAX(id.HistoryDT) FROM InstrumentHistory_Intraday id WHERE id.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '1970-01-01')) as [MaxIntradayDate] + DisplayOrder, + [InstrumentName], + [DisplayName], + [Symbol], + [PostPandemicDilution], + [GMTOffset], + [Currency], + [CurrentPrice], + [InstrumentType], + [ShowInMarquee], + [WatchlistID], + [SingleDayStartDate], + [SingleDayEndDate], + [MinDailyDate], + [MaxDailyDate], + [MinIntradayDate], + [MaxIntradayDate], + [LastSoldDate], + dbo.fn_GetPriceAtDate(dt.InstrumentID, LastSoldDate) as [LastSoldPrice] FROM - Instrument i - /*INNER JOIN Exchange e - ON e.ExchangeID = i.ExchangeID*/ + (SELECT + i.InstrumentID, + i.DisplayOrder, + i.FullName as [InstrumentName], + ISNULL(i.DisplayName, LEFT(i.FullName, 30)) as [DisplayName], + i.Symbol as [Symbol], + i.PostPandemicDilution as [PostPandemicDilution], + i.GMTOffset as [GMTOffset], + i.Currency as [Currency], + i.CurrentPrice as [CurrentPrice], + i.InstrumentType as [InstrumentType], + i.ShowInMarquee as [ShowInMarquee], + i.WatchlistID as [WatchlistID], + i.TradeDayStart as [SingleDayStartDate], + i.TradeDayEnd as [SingleDayEndDate], + ISNULL((SELECT MIN(dd.HistoryDT) FROM InstrumentHistory_Daily dd WHERE dd.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '2030-12-31')) as [MinDailyDate], + ISNULL((SELECT MAX(dd.HistoryDT) FROM InstrumentHistory_Daily dd WHERE dd.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '1970-01-01')) as [MaxDailyDate], + ISNULL((SELECT MIN(id.HistoryDT) FROM InstrumentHistory_Intraday id WHERE id.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '2030-12-31')) as [MinIntradayDate], + ISNULL((SELECT MAX(id.HistoryDT) FROM InstrumentHistory_Intraday id WHERE id.InstrumentID = i.InstrumentID), CONVERT(DATETIME, '1970-01-01')) as [MaxIntradayDate], + (SELECT MAX(h.SoldDate) FROM Holding h WHERE h.InstrumentID = i.InstrumentID AND h.SoldDate IS NOT NULL) as [LastSoldDate] + FROM + Instrument i) as dt ORDER BY - i.DisplayOrder + DisplayOrder END GO GRANT EXECUTE ON usp_GetInstruments TO WebApp_Role @@ -406,7 +488,7 @@ GO CREATE PROCEDURE usp_GetIntradayData (@Symbol varchar(8), @StartDate datetime, @EndDate datetime) AS BEGIN - DECLARE @MAX_DAYS INT = 90 + DECLARE @MAX_DAYS INT = 30 IF DATEDIFF(dd, @StartDate, @EndDate) > @MAX_DAYS BEGIN @@ -761,16 +843,84 @@ GO GRANT EXECUTE ON usp_DeleteHolding TO WebApp_Role GO */ -CREATE PROCEDURE usp_SoldHolding (@HoldingID int, @SoldDate datetime) +CREATE PROCEDURE usp_SoldHolding (@HoldingID int, @SoldDate datetime, @SoldCurrency varchar(8), @SoldProceeds numeric(36, 12)) AS BEGIN - UPDATE Holding SET SoldDate = @SoldDate WHERE HoldingID = @HoldingID + UPDATE + Holding + SET + SoldDate = @SoldDate, + SoldCurrencyID = (SELECT InstrumentID FROM Instrument WHERE Symbol = @SoldCurrency), + SoldProceeds = @SoldProceeds + WHERE + HoldingID = @HoldingID + SELECT @@ROWCOUNT AS [RecordsUpdated] END GO GRANT EXECUTE ON usp_SoldHolding TO WebApp_Role GO +CREATE PROCEDURE usp_SetAccountCashValue (@AccountName varchar(20), @Currency varchar(8), @Value numeric(36, 12)) +AS +BEGIN + DECLARE @AccountID int + DECLARE @CurrencyID int + + SELECT @AccountID = AccountID FROM Account WHERE ShortName = @AccountName + SELECT @CurrencyID = InstrumentID FROM Instrument WHERE Symbol = @Currency + + + IF EXISTS (SELECT NULL FROM Holding WHERE AccountID = @AccountID AND InstrumentID = @CurrencyID) + BEGIN + UPDATE + Holding + SET + NoUnits = @Value + WHERE + AccountID = @AccountID + AND InstrumentID = @CurrencyID + END + ELSE + BEGIN + INSERT Holding ( + AccountID, + InstrumentID, + NoUnits, + PurchasePricePerUnit, + PurchaseDate) + VALUES ( + @AccountID, + @CurrencyID, + @Value, + 1.0, + '2020-01-01') + END + + SELECT + h.HoldingID, + a.ShortName as [AccountName], + i.Symbol as [Symbol], + h.PurchaseDate, + h.NoUnits, + h.PurchasePricePerUnit, + 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 + INNER JOIN Instrument i + ON h.InstrumentID = i.InstrumentID + INNER JOIN Account a + ON a.AccountID = h.AccountID + WHERE + a.AccountID = @AccountID + AND h.InstrumentID = @CurrencyID +END +GO +GRANT EXECUTE ON usp_SetAccountCashValue TO WebApp_Role +GO + CREATE PROCEDURE usp_SwapDisplayOrder (@Symbol1 varchar(8), @Symbol2 varchar(8)) AS BEGIN @@ -800,10 +950,82 @@ GO GRANT EXECUTE ON usp_SwapDisplayOrder TO WebApp_Role GO +CREATE PROCEDURE usp_SetTotalHoldingsValue (@TotalValueGBP money) +AS +BEGIN + DECLARE @Rounded INT = CONVERT(int, FLOOR(@TotalValueGBP)) + DECLARE @EndOfPreviousWeek DATE = DATEADD(day, 1 - DATEPART(weekday, CURRENT_TIMESTAMP), convert(date, CURRENT_TIMESTAMP)) + DECLARE @PreviousDay DATE = DATEADD(day, -1, CONVERT(DATE, CURRENT_TIMESTAMP)) + + IF DATENAME(WEEKDAY, CURRENT_TIMESTAMP) NOT IN ('Saturday', 'Sunday') + BEGIN + IF EXISTS (SELECT NULL FROM TotalHoldingsHistory_Daily WHERE HistoryDate = CONVERT(date, CURRENT_TIMESTAMP)) + BEGIN + UPDATE + TotalHoldingsHistory_Daily + SET + Low = CASE WHEN @Rounded < Low THEN @Rounded ELSE Low END, + High = CASE WHEN @Rounded > High THEN @Rounded ELSE High END, + [Close] = @Rounded + WHERE + HistoryDate = CONVERT(date, CURRENT_TIMESTAMP) + END + ELSE + BEGIN + INSERT TotalHoldingsHistory_Daily (HistoryDate, [Open], Low, High, [Close]) VALUES (CONVERT(date, CURRENT_TIMESTAMP), @Rounded, @Rounded, @Rounded, @Rounded) + END + END + + SELECT + pw.HistoryDate as [PreviousWeekDate], + pw.[Close] as [PreviousWeekClose], + pd.HistoryDate as [PreviousDay], + pd.[Close] as [PreviousClose] + FROM + (SELECT TOP 1 + * + FROM + TotalHoldingsHistory_Daily + WHERE + HistoryDate <= @EndOfPreviousWeek + ORDER BY + HistoryDate DESC) as [pw], + (SELECT TOP 1 + * + FROM + TotalHoldingsHistory_Daily + WHERE + HistoryDate <= @PreviousDay + ORDER BY + HistoryDate DESC) as [pd] +END +GO +GRANT EXECUTE ON usp_SetTotalHoldingsValue TO WebApp_Role +GO + +CREATE PROCEDURE usp_GetTotalHoldingsHistory +AS +BEGIN + SELECT + h.HistoryDate, + h.[Open], + h.[High], + h.[Low], + h.[Close] + FROM + TotalHoldingsHistory_Daily h + ORDER BY + HistoryDate +END +GO +GRANT EXECUTE ON usp_GetTotalHoldingsHistory TO WebApp_Role +GO + CREATE VIEW vHolding AS SELECT h.HoldingID, + i.InstrumentID, a.ShortName as [AccountName], i.Symbol, i.FullName as [InstrumentName], diff --git a/Websites/SharePrices/SharePrices/SharePrices.aspx b/Websites/SharePrices/SharePrices/SharePrices.aspx index 03bf482..5639bd9 100644 --- a/Websites/SharePrices/SharePrices/SharePrices.aspx +++ b/Websites/SharePrices/SharePrices/SharePrices.aspx @@ -26,24 +26,28 @@ - - + + + +