So I have a table called optiontracking with ConID/TimeLog/Ask/Bid table that looks like the following:
ConID
TimeLog
Ask
Bid
1
2020-06-03 10:18:43
0.52
0.55
1
2020-06-03 10:20:41
0.55
0.42
1
2020-06-03 10:23:54
0.60
0.58
1
2020-06-03 10:26:26
0.52
0.51
1
2020-06-03 10:28:57
0.51
0.50
1
2020-06-04 10:25:57
0.65
0.64
1
2020-06-04 10:26:57
0.80
0.79
2
2020-06-03 10:18:43
1.36
1.33
2
2020-06-03 10:20:41
1.38
1.35
2
2020-06-03 10:23:54
1.33
1.32
2
2020-06-03 10:26:26
1.25
1.22
2
2020-06-03 10:28:57
1.20
1.19
What I am trying to get is for each ConID/TimeLog/Ask entry in this table, chronologically next Max(Bid), TimeLog of Max(Bid) while matching the same day and ConID.
I expect to repeat this for Max Ask (but I figure that will need 1 subquery for each group).
So far I have been able to extract the max Bid chronologically after each TimeLog/ask in the dataset using the query below. I want to be able to pull the corresponding timestamp where the MAX(Bid) was retrieved from, but I am hitting a wall without using a second subquery (which I am trying to avoid due to data size).
Here is the query I am using to get the current max Bid per each Ask Chronologically:
SELECT DISTINCT OT.[ConID], OT.[TimeLog], OT.[Ask], MAX(MaxBid.[Bid]) as SellPrice from
(
SELECT * from algotrading.[optiontracking] WHERE YEAR([TimeLog]) <= 2020 and Month([TimeLog]) <= 6
) as OT
LEFT JOIN
(
SELECT [ConID], [Bid], [TimeLog], CONVERT(date, [TimeLog]) as CombDate from algotrading.[optiontracking] WHERE YEAR([TimeLog]) <= 2020 and Month([TimeLog]) <= 6
) as MaxBid
on OT.[ConID] = MaxBid.[ConID] and MaxBid.[CombDate] = CONVERT(date, OT.[TimeLog]) and DATEDIFF(second, OT.[TimeLog], MaxBid.[TimeLog]) > 0
GROUP BY OT.[ConID], OT.[TimeLog], OT.[Ask], CONVERT(date, OT.[TimeLog])
I know there is a way to get the corresponding [TimeLog] for each Max([Bid]), but I can't quite seem to figure it out. The Year/Month filtering on each query is because the dataset is too large and I'm trying to do testing first.
Here is what I would expect as an output from the table above (including the TimeLog for each max bid listed as SellPriceTime below):
ConID
TimeLog
Ask
SellPrice
SellPriceTime
1
2020-06-03 10:18:43
0.52
0.58
2020-06-03 10:23:54
1
2020-06-03 10:20:41
0.55
0.58
2020-06-03 10:23:54
1
2020-06-03 10:23:54
0.60
0.51
2020-06-03 10:26:26
1
2020-06-03 10:26:26
0.52
0.50
2020-06-03 10:23:54
1
2020-06-03 10:28:57
0.51
NULL
NULL
1
2020-06-04 10:25:57
0.65
0.79
2020-06-04 10:26:57
1
2020-06-04 10:26:57
0.80
NULL
NULL
2
2020-06-03 10:18:43
1.36
1.35
2020-06-03 10:20:41
2
2020-06-03 10:20:41
1.38
1.32
2020-06-03 10:23:54
2
2020-06-03 10:23:54
1.33
1.22
2020-06-03 10:26:26
2
2020-06-03 10:26:26
1.25
1.19
2020-06-03 10:28:57
2
2020-06-03 10:28:57
1.20
NULL
NULL
You can use an OUTER APPLY(SELECT TOP 1 ...) to select the max bid row for each ask.
An OUTER APPLY is like a left join to a subselect, where that subselect can apply WHERE conditions, ORDER BY and in this case TOP 1 to get your desired bid. It also allows you to select extract multiple values (Bid and TimeLog in this case), which is an advantage over a simple MAX() function.
I adjusted the "same day" logic to use a condition that checks for TimeLog < start of the next day. The overall date condition in the outer where clause has also been adjusted to be a simple compare. The original logic would have selected the first 6 months in each year 2020 and earlier.
For performance, make sure that you have an index on algotrading.optiontracking(ConID, TimeLog).
SELECT OT.ConID, OT.TimeLog, OT.Ask, MaxBid.SellPrice, MaxBid.SellPriceTime
FROM algotrading.optiontracking as OT
OUTER APPLY (
SELECT TOP 1 OT2.Bid AS SellPrice, OT2.TimeLog AS SellPriceTime
FROM algotrading.optiontracking OT2
WHERE OT2.ConID = OT.ConID
AND OT2.TimeLog > OT.TimeLog -- Later
AND OT2.TimeLog < DATEADD(day, 1, CONVERT(DATE, OT.TimeLog)) -- Before start of next day
ORDER BY OT2.Bid DESC -- Max Bid
) MaxBid
WHERE OT.TimeLog < '2020-07-01' -- Is this what was intended?
Results:
ConID
TimeLog
Ask
SellPrice
SellPriceTime
1
2020-06-03 10:18:43.000
0.52
0.58
2020-06-03 10:23:54.000
1
2020-06-03 10:20:41.000
0.55
0.58
2020-06-03 10:23:54.000
1
2020-06-03 10:23:54.000
0.60
0.51
2020-06-03 10:26:26.000
1
2020-06-03 10:26:26.000
0.52
0.50
2020-06-03 10:28:57.000
1
2020-06-03 10:28:57.000
0.51
null
null
1
2020-06-04 10:25:57.000
0.65
0.79
2020-06-04 10:26:57.000
1
2020-06-04 10:26:57.000
0.80
null
null
2
2020-06-03 10:18:43.000
1.36
1.35
2020-06-03 10:20:41.000
2
2020-06-03 10:20:41.000
1.38
1.32
2020-06-03 10:23:54.000
2
2020-06-03 10:23:54.000
1.33
1.22
2020-06-03 10:26:26.000
2
2020-06-03 10:26:26.000
1.25
1.19
2020-06-03 10:28:57.000
2
2020-06-03 10:28:57.000
1.20
null
null
See this db<>fiddle.
I don't fully understand what you're trying to do but this seems like a case for RANK() and PARTITION BY.
This is not a full answer but with
SELECT ConnId, TimeLog, LastPrice, Ask, Bid,
,Max(LastPrice) OVER (PARTITION BY ConnId) AS MaxLastPrice
,RANK() OVER (PARTITION BY ConnId ORDER BY Bid DESC) AS Rank
from ##Test
you'd get:
ConnId TimeLog LastPrice Ask Bid MaxLastPrice Rank
1 2020-06-04 10:26:57.0000000 10.48 0.80 0.79 10.48 1
1 2020-06-04 10:25:57.0000000 10.48 0.65 0.64 10.48 2
1 2020-06-03 10:23:54.0000000 10.45 0.60 0.58 10.48 3
1 2020-06-03 10:18:43.0000000 10.40 0.52 0.55 10.48 4
1 2020-06-03 10:26:26.0000000 10.42 0.52 0.51 10.48 5
1 2020-06-03 10:28:57.0000000 10.48 0.51 0.50 10.48 6
1 2020-06-03 10:20:41.0000000 10.30 0.55 0.42 10.48 7
2 2020-06-03 10:20:41.0000000 12.05 1.38 1.35 12.15 1
2 2020-06-03 10:18:43.0000000 12.10 1.36 1.33 12.15 2
2 2020-06-03 10:23:54.0000000 12.03 1.33 1.32 12.15 3
2 2020-06-03 10:26:26.0000000 12.13 1.25 1.22 12.15 4
2 2020-06-03 10:28:57.0000000 12.15 1.20 1.19 12.15 5
You can now order by whichever column you wish and pick the records with rank 1, for example.
Here's my test data:
CREATE TABLE ##test (
ConnId INT,
TimeLog DATETIME2,
LastPrice Numeric(5,2),
Ask Numeric(5,2),
Bid Numeric(5,2)
);
Insert into ##test values
(1, '2020-06-03 10:18:43 ', 10.40, 0.52, 0.55),
(1, '2020-06-03 10:20:41 ', 10.30, 0.55, 0.42),
(1, '2020-06-03 10:23:54 ', 10.45, 0.60, 0.58),
(1, '2020-06-03 10:26:26 ', 10.42, 0.52, 0.51),
(1, '2020-06-03 10:28:57 ', 10.48, 0.51, 0.50),
(1, '2020-06-04 10:25:57 ', 10.48, 0.65, 0.64),
(1, '2020-06-04 10:26:57 ', 10.48, 0.80, 0.79),
(2, '2020-06-03 10:18:43 ', 12.10, 1.36, 1.33),
(2, '2020-06-03 10:20:41 ', 12.05, 1.38, 1.35),
(2, '2020-06-03 10:23:54 ', 12.03, 1.33, 1.32),
(2, '2020-06-03 10:26:26 ', 12.13, 1.25, 1.22),
(2, '2020-06-03 10:28:57 ', 12.15, 1.20, 1.19)
I was able to solve this with the way I knew how, and it is faster than the current "better" solution. I would much rather use #T N's answer which is easier to understand and seems way more flexible, but this is query is considerably faster (3.5 mins vs. 8 mins).
For some extra information:
There is roughly 8 million records in this table for data from 6/1/2020 to 7/1/2020
There were no indexes created yet to help with any of these queries.
Any guidance as to why this is a significantly faster query than #T N's answer?
SELECT Prof.[ConID], Prof.[PurchaseTime], Prof.[Ask], Prof.[MaxPriceAfterPurchase], Prof.[MaxPriceAfterPurchase]-Prof.[Ask] as MaxProfit, MIN(SellTimeMax.TimeLog) as SellAtMaxTime
FROM
(
SELECT DISTINCT OT.[ConID], OT.[TimeLog] as [PurchaseTime], OT.[Ask], MAX(MaxBid.[Bid]) as MaxPriceAfterPurchase
from (
SELECT * from algotrading.[optiontracking] WHERE TimeLog < '2020-07-01'
) OT
LEFT JOIN (
SELECT [ConID], [Bid], [TimeLog], CONVERT(date, [TimeLog]) as CombDate from algotrading.[optiontracking] WHERE TimeLog < '2020-07-01'
) MaxBid
on OT.[ConID] = MaxBid.[ConID] and MaxBid.[CombDate] = CONVERT(date, OT.[TimeLog]) and DATEDIFF(second, OT.[TimeLog], MaxBid.[TimeLog]) > 0
GROUP BY OT.[ConID], OT.[TimeLog], OT.[Ask]
) Prof
LEFT JOIN
(
SELECT [ConID], [Bid], [TimeLog], CONVERT(date, [TimeLog]) as CombDate from algotrading.[optiontracking] WHERE TimeLog < '2020-07-01'
) SellTimeMax
ON SellTimeMax.[ConID] = Prof.ConID and SellTimeMax.CombDate = CONVERT(date, Prof.[PurchaseTime]) and SellTimeMax.[Bid] = Prof.[MaxPriceAfterPurchase] and DATEDIFF(second, Prof.[PurchaseTime], SellTimeMax.[TimeLog]) > 0
GROUP BY Prof.[ConID], Prof.[PurchaseTime], Prof.[Ask], Prof.[MaxPriceAfterPurchase], Prof.[MaxPriceAfterPurchase], Prof.[Ask]
stock data
ticker date open high low close volume
--------------------------------------------------------------
AAA 2014-06-16 0.9 0.9 0.89 0.895 542
AAA 2014-06-15 1.32 1.33 1.31 1.32 2792
AAA 2014-06-14 1.19 1.25 1.19 1.25 417
AAA 2014-06-13 0.715 0.715 0.705 0.71 36526
BBB 2014-06-16 0.9 0.9 0.89 0.895 542
BBB 2014-06-15 1.32 1.33 1.31 1.32 2792
BBB 2014-06-14 1.19 1.25 1.19 1.25 417
BBB 2014-06-13 0.715 0.715 0.705 0.71 36526
CCC 2014-06-16 0.9 0.9 0.89 0.895 542
CCC 2014-06-15 1.32 1.33 1.31 1.32 2792
CCC 2014-06-14 1.19 1.25 1.19 1.25 417
CCC 2014-06-13 0.715 0.715 0.705 0.71 36526
I want to select so that it only returns the rows with the latest dates(dynamically), the results with 2014-06-16 for each stock
AAA 2014-06-16 0.9 0.9 0.89 0.895 542
BBB 2014-06-16 0.9 0.9 0.89 0.895 542
CCC 2014-06-16 0.9 0.9 0.89 0.895 542
select Stock_data.*
from Stock_data inner join (
select ticker, max(date) maxdate
from Stock_Data
group by ticker) maxdates
on maxdates.maxdate=date
and maxdates.ticker=Stock_data.ticker
Try this
SELECT T.ticker,T.date,T.open,T.high,T.low,T.close,T.volume
FROM Table1 T
INNER JOIN (
SELECT ticker,Max(date) as MaxDate
FROM Table1
GROUP BY ticker
) S ON S.ticker = T.ticker AND T.date = S.MaxDate
Query like following can be used :
select d.ticker, MAX(d.date) from stock_data d group by d.ticker
Try below query:
WITH TAB AS (
SELECT
TICKER,
DAY,
OPEN,
HIGH,
LOW,
CLOSE,
VOLUME,
RANK() OVER(PARTITION BY TICKER
ORDER BY DAY DESC) AS RANKK
FROM Stocks)
SELECT TICKER, DAY, OPEN, HIGH, LOW, CLOSE, VOLUME
FROM TAB
WHERE TAB.RANKK = 1
using Natural join will do the trick :
select * from
table_name
natural join (select ticker, max(date) as date
from table_name
group by ticker);
I am running into an issue with a simple SQL math operation of qty * price is returning an incorrect value.
This is SQL server 2005. Compatibility is set to 80 for 2000 SQL server.
Any help on understanding why I am having the problem shown below
For example:
Transaction Table:
id price qty
1 2.77 20.00
1 2.77 25.00
1 2.77 10.00
2 0.10 50.00
2 0.10 80.00
3 0.10 50.00
3 0.10 60.00
SQL
Select id, price, qty, (qty * price) from transact
The actual problem was this and it was my fault :(
Select id, CAST(price AS DECIMAL(5,2)), qty, (qty * price) from transact
Returns the following:
id price qty Total
1 2.77 20.00 55.400000 Correct
1 2.77 25.00 69.250000 Correct
1 2.77 10.00 27.700000 Correct
2 0.10 50.00 4.800000 Should be 5.0000
2 0.10 80.00 7.680000 Should be 8.0000
2 0.10 50.00 5.050000 Should be 5.0000
2 0.10 60.00 6.060000 Should be 6.0000
3 39.00 1.00 39.000000 Correct
3 39.00 2.00 78.000000 Correct
3 39.00 3.00 117.000000 Correct
You price is being rounded somewhere. The select you are running is not showing the actual price.
select round(0.096, 2) price, 0.096 * 50.00 total
Result:
price total
0.10 4.80000
I would like to randomly insert in a new temp_table the records from the Initial Table below, grouping them by a new PO number (1234-1, 1234-2,etc..) where each group sum(TKG) is <20 and sum(TVOL) is <0.1
INITIAL TABLE
lineID PO Item QTY Weight Volume T.KG T.VOL
1 1234 ABCD 12 0.40 0.0030 4.80 0.036
2 1234 EFGH 8 0.39 0.0050 3.12 0.040
3 1234 IJKL 5 0.48 0.0070 2.40 0.035
4 1234 MNOP 8 0.69 0.0040 5.53 0.032
5 1234 QRST 9 0.58 0.0025 5.22 0.023
6 1234 UVWX 7 0.87 0.0087 6.09 0.061
7 1234 YZAB 10 0.71 0.0064 7.10 0.064
8 1234 CDEF 6 0.69 0.0054 4.14 0.032
9 1234 GHIJ 7 0.65 0.0036 4.55 0.025
10 1234 KLMN 9 0.67 0.0040 6.03 0.036
NEW Temp_Table should look like:
LineID PO Item QTY Weight Volume T.KG T.VOL
1 1234-1 ABCD 12 0.40 0.0030 4.80 0.036
2 1234-1 EFGH 8 0.39 0.0050 3.12 0.040
5 1234-1 QRST 9 0.58 0.0025 5.22 0.023
3 1234-2 IJKL 5 0.48 0.0070 2.40 0.035
4 1234-2 MNOP 8 0.69 0.0040 5.53 0.032
8 1234-2 CDEF 6 0.69 0.0054 4.14 0.032
6 1234-3 UVWX 7 0.87 0.0087 6.09 0.061
10 1234-3 KLMN 9 0.67 0.0040 6.03 0.036
9 1234-4 GHIJ 7 0.65 0.0036 4.55 0.025
7 1234-4 YZAB 10 0.71 0.0064 7.10 0.064
I can't figure out how to code this...
It's probably a job for a cursor.
The algorithm could basically be like this:
Collect the rows from the initial table one by one, accumulating sum(TKG) and sum(TVOL):
pick out the rows into the temp while the conditions are still met (omit those that exceed either sum);
use lineID as the order;
iterate up to the end of the list.
Upon hitting the end of the table call it a group, then start all over again, omitting the rows that have already been collected into the temp.
Continue while there still are rows not collected.
But I'm too lazy at the moment to give out the actual code, besides it's a homework, and cursors hate me anyway.
The logic of the 1234-1, 1234-2, etc is to break the records into groups that represent a carton. If the order has 100 line items, I may need n cartons (n groups) to pack all the items.