How to calculate the weighted average price of stock trades - php

Given the following table of stock transactions:
TID |DATE |TIME |SYMBOL|SIDE|QUANTITY |PRICE |OPENPOSITION
339791|2014-11-14|12:45:25|ABEV3 |Buy | -900.00|15.920000| -900
339780|2014-11-21|10:54:37|ABEV3 |Sell| 900.00|16.650000| 0
339775|2014-11-24|14:52:59|ABEV3 |Buy | -1500.00|16.950000| -1500
339725|2017-01-20|14:54:26|ABEV3 |Sell| 1500.00|17.280000| 0
339662|2017-02-03|10:43:31|ABEV3 |Buy | -5900.00|17.020000| -5900
339661|2017-02-03|11:44:57|ABEV3 |Buy | -5900.00|17.229492| -11800
339655|2017-02-03|12:37:08|ABEV3 |Sell| 10800.00|17.250000| -1000
339528|2017-02-15|11:04:07|ABEV3 |Buy |-15000.00|17.580000| -16000
339527|2017-02-15|12:07:30|ABEV3 |Sell| 2300.00|17.610000| -13700
339524|2017-02-15|12:10:36|ABEV3 |Sell| 100.00|17.620000| -13600
339522|2017-02-15|12:44:23|ABEV3 |Sell| 14900.00|17.640000| 1300
339518|2017-02-15|12:49:52|ABEV3 |Buy | -2300.00|17.670000| -1000
339474|2017-02-17|11:45:33|ABEV3 |Buy |-20000.00|17.860000| -21000
339472|2017-02-17|13:36:16|ABEV3 |Sell| 20000.00|17.960000| -1000
How can I generate a mysql query to compute the avg weighted price of a transaction whether it is a buy or sell.
In the example above, the trader started buying 900 shares and selling 900 shares for a position balance of 0 (see second row). He does the same thing with 1500 shares, but then he buys and sells several times and remains with 1000 shares left. When calculated by hand, the avg weighed price of purchase is
5900*17.23+5900*17.02+2300*17.67+15000*17.58+20000*17.86/49100 = $17.59
Is there a way to build a query or php functions that considers only the prices of transactions that are still open?

Yes.
If that information is in a database, you'd write a sql select that would be something like:
SELECT price,quantity FROM stock_transactions WHERE ___
But hat do you mean by past closed? Are they closed if they're before the current date? (today)?
If so it'd be:
SELECT price,quantity FROM stock_transactions WHERE CURDATE() >= '2017-02-22'
That'll get those records.
Then run a result set, run through those in a while loop multiplying your price * quantity, add that (+= not assignment) to a variable (that's declared outside that loop fyi). Then repeat.

Select all rows for the given symbol that have OPENPOSITION = 0, and order them by descending date and time.
Read the first row returned and get the date and time. This will be the lower boundary of records you want.
Select all rows for the given symbol with date and time greater than the lower boundary.
Read all returned rows and calculate the weighted average of the share price.

Related

Create view from live stats

I created a sistem to input results from a school basketball tournament. The idea is that after the game the operators will input the result in a format that the system fetches to save in the db in a format like the one below:
Date | Team | Score 1Q | Score 2Q | Score 3Q | Score 4Q | Score OT | Final Score | W | L | Won over Team | Lost to Team | Regular Season? | Finals?
I created a PHP page that calculate many stats from the table above, like Total Wins, Win%, Avg Points, Avg. Points per Quarter, % Turn Around Games when loosing on Half Time or 3Q, % Finals games disputed, Times became champions etc, and many more deep stats.
But I was thinking in creating a View with this information calcalated on the DB and in real time, instead of having the script handles it.
But how can I turn the selects needed from the first table into a working second table with all calculations done whenever we make the selection?
Thanks
#decio, I think your idea about creating a view to calculate those stats is not a bad idea. You might be able to do so with the something similar to the following SQL script:
CREATE VIEW result_stats_view AS SELECT SUM(W) as total_wins, SUM(L) as total_losses FROM precalculate_stats_table_name;
This shows the total wins and losses for the season, but you probably get the idea. Check out MySQL aggregate functions (like average, sum, etc.) here:
https://dev.mysql.com/doc/refman/8.0/en/aggregate-functions.html
Once you have your calculations added to the view then you can simply do query like this to get your calculated data:
SELECT * from result_stats_view

MySQL query to average data if within bounds for graph

I have a large amount of data from a data Logging device stored in a MySQL DB that I want to place on a graph, I want to show a months worth of data - the Logging is per second.
I’m using PHP and the Google Charts library to draw the graph as an image client side.
There is no point trying to display 2,628,000 on a graph on a screen so I want to try and get an SQL query to give an average datapoint for say each hour (3600 down to 1), instead of each second, unless it is out of bounds.
The reason being the whole point in the graph is to show if the value has gone out of bounds and when it did.
The current SQL query to get the data required for last month for example is below, the first problem is PHP is hitting its memory limit before its able to return the data:
SELECT Tms, Hz FROM log WHERE Tms >= ".$start." AND Tms <=".$finish." ORDER BY Tms ASC
The average value should be for example 60, the upper limit is 61.5 and the lower limit is 58.5 - any value outside of these should be returned as-is otherwise the hours worth of data should be returned as an average for that hour.
EDIT: To answer the comments:
DB structure is:
ID - double - AUTO_INCREMENT
Tms - timestamp
Hz - float
Example Data is:
ID | Tms | Hz
1 | 1559347082 | 59.91
2 | 1559347083 | 59.98
3 | 1559347084 | 60.53
4 | 1559347085 | 62.03
5 | 1559347086 | 61.11
6 | 1559347087 | 60.93
7 | 1559347088 | 60.88
.......
3606 | 1559350686 | 59.99
The expected results would be to have an array of results, all of the values within an hour as an average, unless there is a value out of bounds.
So for the data above, items 1,2,3 would be returned with the average Tms: 1559347083 and average Hz: 60.14, but the next value in the array of results would be Tms: 1559347085 and Hz: 62.03.
Results:
Tms: 1559347083 | Hz: 60.14
Tms: 1559347085 | Hz: 62.03
Tms: 1559348886 | Hz: 60.17
The maximum amount of points to be averaged or grouped together would be 3600 rows = 1 hour so the graph does show some movement.
One of the current errors when trying to select a large amount of data:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes)
This is happening as the result is being placed into an array so I can add the values for the bounds so there is a clear line on the graph:
while($row = $result->fetch_assoc()) {
$dataPoint = array($row['Tms'], '58.5', $row[$graph], '61.5');
....
array_push($dataPoints, $dataPoint);
This array ($dataPoints) then gets passed to a function to either output as JSON or output as CSV using fputcsv
It is not logical, or useful, to have one query that does give both, hourly averages, and individual out of bounds values. This requires two queries. So let's start with the first, the hourly average:
SELECT
COUNT(ID) AS CountID,
DATE(Tms) AS DateTms,
HOUR(Tms) AS HourTms,
AVG(Hz) AS AvgHz
FROM
log
WHERE
Tms >= '2019-01-01 12:00:00' AND
Tms <= '2019-12-12 12:00:00'
GROUP BY
HOUR(Tms)
ORDER BY
Tms ASC
I've put real dates in the WHERE conditions, instead of the undocumented variables $start and $finish, but these can, of course, be replace. I've added a counter, because it is always useful, and finally, because we report for each hour of the day, I have added a date. The GROUP BY HOUR(Tms) does the grouping by whole hours.
The second query is about the out of bouds values. It is simply:
SELECT
ID,
Tms,
Hz
FROM
log
WHERE
Tms >= '2019-01-01 12:00:00' AND
Tms <= '2019-12-12 12:00:00' AND
(Hz < 58.5 OR Hz > 61.5)
ORDER BY
Tms ASC
You can easily combine the results of these two queries into one array with PHP. However...
I am worried that the last query might produce too much data when there are too much out of bound values. And that's probably what you're saying in your later addition to the question. To solve this you could work with an hourly average of the out of bounds values. You would have to use two queries for this, one for values below the lower limit and one for those above the upper limit. I'll show the first one here:
SELECT
COUNT(ID) AS CountID,
DATE(Tms) AS DateTms,
HOUR(Tms) AS HourTms,
AVG(Hz) AS AvgHz
FROM
log
WHERE
Tms >= '2019-01-01 12:00:00' AND
Tms <= '2019-12-12 12:00:00' AND
Hz < 58.5
GROUP BY
HOUR(Tms)
ORDER BY
Tms ASC
This looks very much like the first query, which is a good thing. The only addition is the range limiting of the Hz value. The other query simply has Hz > 61.5. The results of the three queries can be collected in an array and displaying in a graph.
The three queries could be forced into one query, but I don't see the advantage of that. With three separate queries you could, for instance, write a PHP function that does the query and gets the results, and all you need to vary, using function parameters, is range limiting and the start/finish times.
Finally a bit about your database. I see you use doubles for the ID, that should probably be an integer. Also don't forget to put indexes on Tms and Hz otherwise your queries might be very slow.

Get beginning balance based on selected month in php

I need to generate beginning balance for the selected month. for example, I'm having a list of pre-allocated serial numbers/ids/rows 1000 to 1999. In February I'm using 800 numbers (from id 1000-1799). Thus, my next months beginning balance would be 200.
In my DB I'm having three relevant columns: id, created_date and updated_date.
If I use only 50 numbers in March (1800-1849), then beginning balance for April is 150 (I already used up 850 of the pre-allocated 1000 ids). How to query the DB to fetch the number of remaining pre-allocated ids?
This example is based on the amount of information you provided and assumes you don't need to filter by user id or any other data, but that you do have a numeric row id.
SELECT (1000 - COUNT(*)) AS balance FROM table_name WHERE id BETWEEN 1000 AND 1999
If that is not the case, then please add the result of the
explain table_name command, where you substitute table_name with the actual name of the table.

Select top 5 MySQL after division of two rows

I have a rating system that takes the rating of 1-5 then increments the number of votes and adds to a total number of rating. This is problematic for my top 5 leaderboard which currently provides Xml through a php web service from the MySQL database with this query:
FROM ratings ORDER BY totalRating DESC LIMIT 5
Now obviously this isn't going to work.
Is there a way to do the division of totalRating by noRating and THEN return order by?
I'm trying to keep this to the database level. Hopefully it's possible.
Edit:
So let's say my table ratings has two records:
Name | cRating | tRating //current number of ratings and total
Tv1 | 2 | 10
Tv2 | 3 | 9
I need to do tRating / cRating then sort them into the top 5 shows
Desired result is to return the top 5 averagely rated results (sorry for the terrible formatting I'm on my phone)
You can use an arithmetic expression in the order by. So this might do what you want:
order by tRating / nullif(cRating, 0) desc

MySQL select records that sums

I am using MySQL and PHP. I have a table that contains the columns id and quantity. I would like to retrieve the id of the row that is the last to sum quantity as it reaches the number 40 at sum. To be more specific. I have 3 rows in the database. One with quantity 10, one with quantity 30 and one with quantity 20. So if I sum the quantities to have the result 40, I would sum up the first two witch means: 10 + 30 = 40. That way, the last Id that is used to sum the number 40 is 2. I just want to know the id of the last row that is used to complete the sum of 40.
I would give further details if asked. THANK YOU!!
Let me put it this way:
I really have 6 products in my hand. The first one came to my possession on the date of 10, the next 3 came on the date of 11 and the last 2 came on 12.
Now, I want to sell 3 products from my stock. And want to sell them in the order that they came. So for the customer that wants 3 products I would sell him the product that came on 10 and 2 products from the ones that came on 11.
For the next customer that wants 2 products, I would sell him one product from the date of 11 that remains from the last order of 3 products, and another one from the ones on 12.
The question is how would I know which price had each product I sold ? I thought that if I can find out which rows sums up every requested quantity, I would know where to start the sum every time I want to deliver an order. So first I would look which rows sums up 3 products and keep the entry id. For the next order I would start the count from that ID and sum until it sums up the second order of 2 products and so on. I thought that this way, I can keep track of the incoming prices that each product had. So I won't sell the products from the date of 12 at a price made up using the first prices.
I hope you understand. I just need to know what price had any of my products so I would know that the first products would have one price but as the product prices raises, I must raise my prices too...So the last products that came must be sold for a higher price. I can only achieve that if I keep track of this...
Thank you very much.
Nobody ? Or, even easier: MySQL should select the needed rows for SUM(quantity) to be higher or equal with 40 for example. And then to get me the id of the last row that participated at the sum process.
Have a third column with a running total. Then you can simply return the last row where the running total <= your target value.
So your table should look like:
ID Quantity RunningTotal
1 10 10
2 30 40
3 20 60
NOTE: If you delete a row in the table, remember to update all subsequent rows RunningTotal -= DeletedRow.Quantity!
I don't understand your question too well. Can you try rewording it more properly? From what I interpret, here's the structure of your database:
ProductID ArrivalDate
1 10
2 11
3 11
4 11
5 12
6 12
Now you are asking, "how would I know which price had each product I sold"? Which sorta confuses me, since each value in the database has no price attribute. Shouldn't your database look like this:
ProductID ArrivalDate Price
1 10 100
2 11 200
3 11 300
4 11 300
5 12 400
6 12 400
Personally, I think your idea to find out price sold is flawed. It would make more sense to add a few more fields to your database:
ProductID ArrivalDate Price InStock DateSold
1 10 100 Yes 17
2 11 200 Yes 17
3 11 300 Yes 18
4 11 300 Yes 18
5 12 400 no
6 12 400 no
In changing your database, you can easily keep track of when a product arrives, the date sold, its price, maybe quantity (I can't tell if its an actual field or not).
Furthermore, you can simplify and make your life easier by separating the sql queries, or even adding some code to do some of the work for you.
Relying on table ID's is probably a bad idea for this, but if that is how it is really done, you could try something like this (not tested):
SELECT yourTableA.id
FROM yourTable AS yourTableA
JOIN yourTable AS yourTableB
WHERE ( yourTableA.value + yourTableB.value ) = 40
AND yourTableA.id != yourTableB.id
ORDER BY yourTableA.id
This type of solution will only work if your expecting that you only need two rows ever to equal your target sum. Since this is most likely not the case, your best bet is probably to try and get all of the rows and do this programaticly on the returned data.
The Running Total solution posted by lc is also a good option although I generally try to avoid storing calculated data unless I absolutely have to.
Based on the updated information from this request, I have an alternate answer.
It doesn't sound so much like you care about the inventory. You care more about when the products came in.
SELECT *
FROM product
ORDER BY product.receivedData
Process each record as they come in, store the price for that record, and keep going for as long as you need to until you reach the number of items you need. You should end up with a list of items, the number of inventory at that level and the price at that level.

Categories