I have data that looks like this:
Trader Name | Currency_Code | Counterparty | Traded_Amount | Total_Traded_Volume | Baseline_Avg | Variance
Jules Winnfield | GBP | GOLD | 10000 | 30000 | 10000 | 0
Jules Winnfield | GBP | BARC | 8000 | 30000 | 11000 | -3000
Jules Winnfield | GBP | JPMORG | 12000 | 30000 | 9000 | +3000
Jules Winnfield | EUR | GOLD | 15000 | 27000 | 6000 | 21000
Jules Winnfield | EUR | BARC | 2000 | 27000 | 12500 | -10500
Jules Winnfield | EUR | JPMORG | 10000 | 27000 | 8500 | +1500
Let me take a minute to briefly explain this dataset:
- The trader has placed a collective £30000 worth of trades across three counterparties - say in this example, goldman sachs, barclays and JP Morgan.
- The individual amounts, i.e. £10000, £8000 and £12000 are a simple
sum()
aggregation performed on the individual trades themselves, with the £30000 obtained via another aggregation usingOVER (PARTITION BY TRADER_NAME, CURRENCY_CODE)
- The baseline_average calculates the average trading volume with all other counterparties - for e.g. Jules has traded £8000 with Barclays, and the average trading volume with the other counterparties (Goldman Sachs and JP Morgan) is £11000. The variance is the difference between traded_amount and baseline_average.
The code used to generate the above output is:
SELECT
OT.TRADER_NAME,
OT.CURRENCY_CODE,
OT.COUNTERPARTY,
SUM(OT.TRADED_AMOUNT) AS TRADED_AMOUNT,
SUM(OT.TRADED_AMOUNT) OVER (PARTITION BY OT.TRADER_NAME, OT.CURRENCY_CODE) AS TOTAL_TRADED_VOL,
(SUM(OT.TRADED_AMOUNT) OVER (PARTITION BY OT.TRADER_NAME, OT.CURRENCY_CODE)-
SUM(OT.TRADED_AMOUNT))/NULLIF(SUM(1) OVER (PARTITION BY OT.TRADER_NAME, OT.CURRENCY_CODE)-1),0)
AS BASELINE_AVG,
SUM(OT.TRADED_AMOUNT) - (SUM(OT.TRADED_AMOUNT) OVER (PARTITION BY OT.TRADER_NAME,
OT.CURRENCY_CODE)-SUM(OT.TRADED_AMOUNT))/NULLIF(SUM(1) OVER (PARTITION BY OT.TRADER_NAME,
OT.CURRENCY_CODE)-1),0) AS VARIANCE
FROM ORDERS_TRADES_DATA OT
GROUP BY OT.TRADER_NAME, OT.CURRENCY_CODE, OT.COUNTERPARTY, FX.FX_RATE
So far so good. This enables me to slice the data as long as I specify the currency I am interested in. However, I would like to now add a column that aggregates the trader's entire trading volume into the USD equivalent- essentially, one traded_volume per user in USD as a window function - which I can use for analysis. I have the FX rates stored in a separate table and can apply a join. Have tried running the following query:
SELECT
OT.TRADER_NAME,
OT.CURRENCY_CODE,
OT.COUNTERPARTY,
SUM(OT.TRADED_AMOUNT) AS TRADED_AMOUNT,
SUM(OT.TRADED_AMOUNT) OVER (PARTITION BY OT.TRADER_NAME, OT.CURRENCY_CODE) AS TOTAL_TRADED_VOL,
(SUM(OT.TRADED_AMOUNT) OVER (PARTITION BY OT.TRADER_NAME, OT.CURRENCY_CODE)-
SUM(OT.TRADED_AMOUNT))/NULLIF(SUM(1) OVER (PARTITION BY OT.TRADER_NAME, OT.CURRENCY_CODE)-1),0)
AS BASELINE_AVG,
SUM(OT.TRADED_AMOUNT) - (SUM(OT.TRADED_AMOUNT) OVER (PARTITION BY OT.TRADER_NAME,
OT.CURRENCY_CODE)-SUM(OT.TRADED_AMOUNT))/NULLIF(SUM(1) OVER (PARTITION BY OT.TRADER_NAME,
OT.CURRENCY_CODE)-1),0) AS VARIANCE,
SUM(OT.TRADED_AMOUNT)/FX.FX_RATE AS TRADED_AMOUNT_USD,
SUM((SUM(OT.TRADED_AMOUNT)/FX.FX_RATE) AS TOTAL_TRADED_VOL_USD,
(SUM(OT.TRADED_AMOUNT)/FX.FX_RATE OVER (PARTITION BY OT.TRADER_NAME)-
SUM(OT.TRADED_AMOUNT)/FX.FX_RATE)/NULLIF(SUM(1) OVER (PARTITION BY OT.TRADER_NAME)-1),0)
AS BASELINE_AVG_USD,
SUM((SUM(OT.TRADED_AMOUNT)/FX.FX_RATE) - (SUM(OT.TRADED_AMOUNT)/FX.FX_RATE OVER (PARTITION BY
OT.TRADER_NAME)-SUM(OT.TRADED_AMOUNT)/FX.FX_RATE)/NULLIF(SUM(1) OVER (PARTITION BY
OT.TRADER_NAME)-1),0) AS VARIANCE_USD
FROM ORDERS_TRADES_DATA OT
LEFT JOIN FX_RATES_TABLE FX ON OT.CURRENCY_CODE = FX.ASSET_CURRENCY_CODE
GROUP BY OT.TRADER_NAME, OT.CURRENCY_CODE, OT.COUNTERPARTY, FX.FX_RATE
... does not work as I get the error:
cannot perform an aggregate function on an expression containing an aggregate or subquery.
How an I achieve my objective here?