我有一张充满库存和期权头寸的表格(“期权头寸”是期权到期日和行使价的组合)。列:
userID - the person who owns the position
stock_symbol - the stock they own
call_expiration - expiration date for a call option they've sold against the stock
call_strike - strike price for the same call option
用户可以为同一stock_symbol拥有多个股票头寸,如果确实如此,则他们可能针对该同一品种写有不同的看涨期权。例如,用户399在AAPL中有3个职位,每个职位都有不同的通话选项:
+---------+--------------+-----------------+-------------+
| user_id | stock_symbol | call_expiration | call_strike |
+---------+--------------+-----------------+-------------+
| 399 | AAPL | 2018-07-20 | 185 |
| 399 | AAPL | 2018-07-20 | 190 |
| 399 | AAPL | 2018-08-17 | 180 |
| 399 | X | 2018-07-20 | 13 |
| 802 | AAPL | 2018-07-20 | 190 |
| 802 | X | 2019-01-18 | 14 |
| 802 | MU | 2018-07-20 | 38 |
| 802 | MIC | 2018-07-20 | 42.5 |
| 802 | AAPL | 2018-07-20 | 190 |
| 1079 | MU | 2018-08-17 | 39 |
| 1079 | X | 2018-07-20 | 14 |
我想知道哪些股票是最常持有的股票,但我希望每个用户有1票(在上面的数据符号X中获胜,因为其中有3个用户有仓位; AAPL拥有更多仓位,但它们仅由所有者拥有2个用户)。因此,如果同一用户在同一stock_symbol中有多个头寸,则该股票_symbol仅计为1票。如果频率有关联,则按符号字母顺序排序。也许有一种更简单的方法,但这可行:
SELECT stock_symbol, COUNT(*) AS symbol_count FROM
(SELECT DISTINCT(user_id), stock_symbol FROM user_positions) AS temp
GROUP BY stock_symbol
ORDER BY symbol_count DESC, stock_symbol ASC LIMIT 10;
然后,我想知道每种流行符号最常用的失效日期。这是我如何为硬编码的stock_symbol(AAPL)找到它的方法。如果有平局,则最早的到期日期将获胜:
SELECT call_expiration, COUNT(*) AS exp_count FROM positions
WHERE stock_symbol='AAPL'
GROUP BY call_expiration
ORDER BY exp_count DESC, call_expiration ASC;
然后,最后,我想知道给定符号和到期日期最常见的strike_price。这是我为硬编码符号和有效期找到它的方法。如果有平局,则最低执行价格为准:
SELECT call_strike, COUNT(*) AS strike_count FROM positions
WHERE stock_symbol='AAPL' AND call_expiration = '2018-07-20'
GROUP BY call_strike
ORDER BY strike_count DESC, call_strike ASC;
这些工作,我可以将这些调用放入php脚本中,并循环浏览第一个查询的结果(该查询生成了10个最常用的stock_symbols),但是我想知道是否有办法让mysql来完成所有工作对我来说。
最终目标是一个像这样的表:
popular position #1: S1 E1 K1
popular position #2: S2 E2 K2
popular position #3: S3 E3 K3
位置:
S1 = the most commonly held stock_symbol when each user gets 1 vote
E1 = the most common expiration date across all positions for symbol S1 (if a user has multiple positions for that symbol then you can consider all of them)
K1 = the most common call_strike for all positions where the symbol and expiraiton date are fixed at S1 and E1. (if a user has multiple positions for that symbol then you can consider all of them)
我不确定这是否是一个坏主意,但是我想到了在查询中创建中间列以连接call_expiration + call_strike,或者可能是所有3:symbol + expiration + strike;不能完全弄清楚,因为在第一种情况下(最流行的符号)我希望用户每个人只有1票,但是在接下来的2个查询中(最有效的到期日和该日期的最常见执行价格)可以考虑所有用户位置,即使同一符号的位置超过1个也是如此。在单个查询中可能做太多事情了?
--- 18/6/24在下面添加了示例数据---
CREATE TABLE test_positions (
position_id int unsigned auto_increment,
user_id int unsigned,
stock_symbol varchar(10),
call_expiration date,
call_strike float,
primary key (position_id)
);
INSERT INTO test_positions
(user_id, stock_symbol, call_expiration, call_strike)
VALUES
(399, 'AAPL', '2018-07-20', 185),
(399, 'AAPL', '2018-07-20', 190),
(399, 'AAPL', '2018-08-17', 190),
(399, 'AAPL', '2018-09-21', 180),
(399, 'X', '2018-07-20', 35),
(802, 'X', '2018-07-20', 35.5),
(1079, 'X', '2018-07-20', 35),
(1079, 'X', '2018-07-20', 35.5),
(1079, 'AAPL', '2018-07-20', 190),
(1079, 'AAPL', '2018-07-20', 185),
(1079, 'MRK', '2018-07-20', 62.5),
(1079, 'MRK', '2018-08-17', 60);
使用此数据所需的查询结果是:
+--------------+-----------------+-------------+
| stock_symbol | call_expiration | call_strike |
+--------------+-----------------+-------------+
| X | 2018-07-20 | 35 |
| AAPL | 2018-07-20 | 190 |
| MRK | 2018-07-20 | 62.5 |
+--------------+-----------------+-------------+
因为符号X由3个用户持有。即使APL拥有更多职位,但在APL中只有2个唯一的用户具有职位,因此我们要说X比APL更受欢迎。
在符号X的4个位置中,最常见的call_expiration为2018-07-20,如果我们查看所有符号为X且call_expiration为2018-07-20的call_strikes,则其为平局(2有35和2的值为35.5),因此我们要选择2中的较低者。
在MRK的2个职位中,它与call_expiration并列(两个日期各1个),因此我们选择2个中的较早者(2018-07-20),然后查看符号MRK,其中call_expiration为2018-07-20最常见(唯一)call_strike为62.50。