
ധനകാര്യ ഡേറ്റ വെയർഹൌസുകൾക്കുള്ള SQL
ഘടനാപരമായ ധനകാര്യ ഡേറ്റ ക്വറി ചെയ്യുക, അഗ്രിഗേറ്റ് ചെയ്യുക, വിശകലനം ചെയ്യുക
ഫിനാൻഷ്യൽ ഡാറ്റയുടെ ഭാഷ SQL ആയിരിക്കുന്നത് എന്തുകൊണ്ട്
ഓരോ ട്രേഡും, ഓരോ tick-ഉം, ഓരോ order book അപ്ഡേറ്റും — ഫിനാൻഷ്യൽ മാർക്കറ്റുകൾ വളരെ വലിയ അളവ് structured ഡാറ്റ ഉണ്ടാക്കുന്നു. നാല് ദശാബ്ദത്തിലധികമായി, SQL (Structured Query Language) ആ ഡാറ്റ query ചെയ്യാനും, transform ചെയ്യാനും, analyze ചെയ്യാനും ഉള്ള പ്രധാന tool ആണ്. ഇത് glamorous അല്ല. trendy അല്ല. പക്ഷേ ഒരു portfolio manager "കഴിഞ്ഞ Tuesday 2 PM മുതൽ 3 PM UTC വരെ ETH ട്രേഡുകളിലെ എന്റെ average fill price എന്തായിരുന്നു?" എന്ന് ചോദിക്കുമ്പോൾ, ഉത്തരം SQL-ൽ നിന്നാണ് വരുന്നത്.
ഫിനാൻഷ്യൽ ഡാറ്റ അന്തർലീനമായി relational ആണ്. ഒരു ട്രേഡ് ഒരു ഓർഡറിനെ റെഫർ ചെയ്യുന്നു, അത് ഒരു account-നെ, അത് ഒരു user-ന് belong ചെയ്യുന്നു. Positions instrument-കളുമായി ബന്ധപ്പെട്ടിരിക്കുന്നു; instruments market-കളുമായി ബന്ധപ്പെട്ടിരിക്കുന്നു. relational model — rows, columns, foreign keys വഴി connect ചെയ്ത tables — ഈ ബന്ധങ്ങളിലേക്ക് സ്വാഭാവികമായി map ചെയ്യുന്നു. അതുകൊണ്ടാണ് PostgreSQL, MySQL, SQL Server പോലുള്ള relational database-കൾ Goldman Sachs മുതൽ GaiaEx വരെ ഫിനാൻഷ്യൽ ഇൻഫ്രാസ്ട്രക്ചറിന്റെ backbone ആയി തുടരുന്നത്.
SQL-ന്റെ ശക്തി അതിന്റെ declarative സ്വഭാവത്തിലാണ്: നിങ്ങൾക്ക് എന്ത് വേണം എന്ന് വിവരിക്കുന്നു, എങ്ങനെ അത് ലഭിക്കണം എന്നല്ല. Database engine optimal execution plan കണ്ടെത്തുന്നു. നിങ്ങളുടെ trade history table-ന് 500 മില്യൺ rows ഉള്ളപ്പോൾ, ഒരു സെക്കൻഡിന് താഴെ results ആവശ്യമുള്ളപ്പോൾ ഇത് വളരെ പ്രധാനമാണ്. ശരിയായ query എഴുതുക, ശരിയായ index ബിൽഡ് ചെയ്യുക, SQL ഡെലിവർ ചെയ്യും — ഒരു local PostgreSQL instance-ലോ cloud-scale data warehouse-ലോ run ചെയ്യുന്നത് ആയാലും.
SELECT, JOIN, WHERE: Trade Data Query ചെയ്യൽ
ഒരു concrete schema-യിൽ നിന്ന് ആരംഭിക്കാം. GaiaEx പോലുള്ള ഒരു പ്ലാറ്റ്ഫോമിലെ trades table സങ്കൽപ്പിക്കുക:
CREATE TABLE trades (
trade_id BIGINT PRIMARY KEY,
user_id INT NOT NULL,
symbol VARCHAR(20) NOT NULL,
side VARCHAR(4) NOT NULL, -- 'buy' or 'sell'
price NUMERIC(18,8) NOT NULL,
quantity NUMERIC(18,8) NOT NULL,
fee NUMERIC(18,8) DEFAULT 0,
executed_at TIMESTAMPTZ NOT NULL
);
ഏറ്റവും അടിസ്ഥാനപരമായ operation filtering-ഓടെയുള്ള SELECT statement ആണ്. കഴിഞ്ഞ 24 മണിക്കൂറിൽ $3,000-ന് മുകളിലുള്ള എല്ലാ ETH-USD buy trades കണ്ടെത്താൻ:
SELECT trade_id, price, quantity, executed_at
FROM trades
WHERE symbol = 'ETH-USD'
AND side = 'buy'
AND price > 3000
AND executed_at > NOW() - INTERVAL '24 hours'
ORDER BY executed_at DESC;
JOIN-കൾ ബന്ധപ്പെട്ട table-കൾ connect ചെയ്യുന്നു. നിങ്ങൾക്ക് ഒരു accounts table ഉണ്ടെന്നും, account tier അനുസരിച്ച് trading volume കാണണമെന്നും കരുതുക:
SELECT a.tier, COUNT(*) AS trade_count,
SUM(t.price * t.quantity) AS total_volume
FROM trades t
JOIN accounts a ON t.user_id = a.user_id
WHERE t.executed_at > NOW() - INTERVAL '30 days'
GROUP BY a.tier
ORDER BY total_volume DESC;
ഈ query-കൾ ഫിനാൻഷ്യൽ analyst-കൾ, risk team-കൾ, compliance officer-കൾ എന്നിവരുടെ ദിവസേനയുള്ള റൊട്ടിയാണ്. അവ master ചെയ്താൽ നിങ്ങളുടെ ഡാറ്റയിൽ അടങ്ങിയിരിക്കുന്ന ഏത് ചോദ്യത്തിനും ഉത്തരം കണ്ടെത്താം.
Window Function-കൾ: Analyst-ന്റെ Secret Weapon
Window function-കൾ ആണ് ഫിനാൻസിൽ SQL beginner-കളെയും SQL practitioner-കളെയും വേർതിരിക്കുന്നത്. Result ഒരു single aggregated value-ലേക്ക് collapse ചെയ്യാതെ, current row-മായി ബന്ധപ്പെട്ട rows-ന്റെ ഒരു set-ൽ calculations perform ചെയ്യാൻ അവ അനുവദിക്കുന്നു. നിങ്ങളുടെ ഡാറ്റയിലുടനീളമുള്ള "running computations" ആയി അവയെ കരുതുക.
ഫിനാൻഷ്യൽ analysis-ൽ ഏറ്റവും കൂടുതൽ ഉപയോഗിക്കുന്ന window function-കൾ:
- ROW_NUMBER() — ഒരു partition-നുള്ളിൽ ഓരോ row-ക്കും sequential integer assign ചെയ്യുന്നു. Deduplication-ന് അല്ലെങ്കിൽ ഓരോ symbol-ന്റെയും Nth trade select ചെയ്യാൻ ഉപകാരപ്രദമാണ്.
- LAG(), LEAD() — previous അല്ലെങ്കിൽ next row-ന്റെ value access ചെയ്യുന്നു. trade-to-trade returns compute ചെയ്യാനോ time-series ഡാറ്റയിലെ gap-കൾ detect ചെയ്യാനോ അത്യാവശ്യമാണ്.
- SUM() OVER () — Running totals. Cumulative volume, cumulative P&L, അല്ലെങ്കിൽ running position size compute ചെയ്യുന്നു.
- AVG() OVER (ROWS BETWEEN) — SQL-ൽ നേരിട്ട് moving average-കൾ. Python ആവശ്യമില്ല.
ഒരു practical ഉദാഹരണം — BTC-ക്ക് trade-to-trade price change-ഉം running position-ഉം compute ചെയ്യുന്നു:
SELECT executed_at, price, quantity, side,
price - LAG(price) OVER (ORDER BY executed_at) AS price_change,
SUM(CASE WHEN side = 'buy' THEN quantity ELSE -quantity END)
OVER (ORDER BY executed_at) AS running_position
FROM trades
WHERE symbol = 'BTC-USD'
ORDER BY executed_at;
Window function-കൾ നിങ്ങളുടെ row count കുറയ്ക്കുന്നില്ല — GROUP BY-ക്ക് വിരുദ്ധമായി, ഓരോ input row-ഉം ഒരു output row ഉണ്ടാക്കുന്നു. Granularity നഷ്ടപ്പെടാതെ detailed trade log-കളിലേക്ക് analytical column-കൾ ചേർക്കാൻ ഇത് perfect ആക്കുന്നു. നിങ്ങളുടെ ഡാറ്റ "summarize" ചെയ്യുന്നതിന് പകരം "enrich" ചെയ്യുന്നത് പോലെ അവയെ കരുതുക.
OHLCV aggregation-ന് — candlestick chart-കളുടെ അടിസ്ഥാനം — GROUP BY time-bucketing-ഓടെയും standard aggregate-കളോടെയും combine ചെയ്യാം:
SELECT date_trunc('hour', executed_at) AS bucket,
(ARRAY_AGG(price ORDER BY executed_at))[1] AS open,
MAX(price) AS high,
MIN(price) AS low,
(ARRAY_AGG(price ORDER BY executed_at DESC))[1] AS close,
SUM(quantity) AS volume
FROM trades
WHERE symbol = 'ETH-USD'
GROUP BY bucket
ORDER BY bucket;CTE-കൾ: സങ്കീർണ്ണമായ Analytical Query-കൾ Compose ചെയ്യൽ
Common Table Expressions (CTE-കൾ) ഒരു സങ്കീർണ്ണമായ query-യെ named, readable stage-കളായി — പ്രോഗ്രാമിംഗിലെ function-കൾ പോലെ — ബ്രേക്ക് ചെയ്യാൻ അനുവദിക്കുന്നു. WITH keyword-ഓടെ അവ introduce ചെയ്യപ്പെടുന്നു, sequentially പരസ്പരം refer ചെയ്യാൻ കഴിയും.
നിങ്ങളുടെ top 10 ഏറ്റവും profitable trading days identify ചെയ്യണം എന്ന് കരുതുക, പക്ഷേ profitability ഫീസ് ഉൾപ്പെടെയുള്ള ദിവസേനയുള്ള net P&L compute ചെയ്യേണ്ടതുണ്ട്. CTE-കൾ ഉപയോഗിച്ച്, ഇത് step by step ബിൽഡ് ചെയ്യാം:
WITH daily_trades AS (
SELECT DATE(executed_at) AS trade_date,
SUM(CASE WHEN side = 'sell' THEN price * quantity
ELSE -price * quantity END) AS gross_pnl,
SUM(fee) AS total_fees
FROM trades
WHERE user_id = 42
GROUP BY DATE(executed_at)
),
daily_pnl AS (
SELECT trade_date,
gross_pnl - total_fees AS net_pnl,
SUM(gross_pnl - total_fees) OVER (ORDER BY trade_date) AS cumulative_pnl
FROM daily_trades
)
SELECT trade_date, net_pnl, cumulative_pnl
FROM daily_pnl
ORDER BY net_pnl DESC
LIMIT 10;
ഓരോ CTE-യും ഒരു paragraph പോലെ വായിക്കുന്നു. daily_trades raw trades-നെ ദിവസേനയുള്ള summary-കളിലേക്ക് aggregate ചെയ്യുന്നു. daily_pnl net P&L-ഉം ഒരു running total-ഉം compute ചെയ്യുന്നു. അവസാന SELECT top 10 ദിവസങ്ങൾ പിക്ക് ചെയ്യുന്നു. ഇത് ഒരു single monolithic subquery-യുമായി compare ചെയ്യുക — CTE version maintainable, testable, self-documenting ആണ്.
Production ഫിനാൻഷ്യൽ സിസ്റ്റങ്ങളിൽ, CTE-കൾ regulatory reporting-ന് (accounts-കളിലുടനീളം margin requirements aggregate ചെയ്യുന്നത്) മുതൽ real-time dashboard query-കൾക്ക് (GaiaEx-ൽ rolling 24-hour volume compute ചെയ്യുന്നത്) വരെ എല്ലാ കാര്യത്തിനും ഉപയോഗിക്കുന്നു. well-factored കോഡ് compose ചെയ്യുന്ന അതേ രീതിയിൽ അവ compose ചെയ്യുന്നു — ഓരോ ലെയറും മുൻപത്തേതിന്റെ മുകളിൽ ബിൽഡ് ചെയ്യുന്നു.
Time-Series Performance-നുള്ള Indexing-ഉം Partitioning-ഉം
ഒരു query അതിന് പിന്തുണ നൽകുന്ന index-ത്തോളം മാത്രമേ വേഗതയുള്ളതാകൂ. ശരിയായ index ഇല്ലാതെ, ഒരു ലളിതമായ WHERE clause പോലും table-ലെ ഓരോ row-ഉം read ചെയ്യുന്ന sequential scan-ന് നിർബന്ധിക്കുന്നു. 500 മില്യൺ rows-ൽ, അത് മില്ലിസെക്കൻഡുകൾക്ക് പകരം മിനിറ്റുകളാണ്.
ഫിനാൻഷ്യൽ time-series ഡാറ്റയ്ക്ക്, ഏറ്റവും critical index pattern (symbol, executed_at)-ൽ ഒരു composite B-tree index ആണ്:
CREATE INDEX idx_trades_symbol_time
ON trades (symbol, executed_at DESC);
ഈ single index മുൻഭാഗം analytical query-കൾ accelerate ചെയ്യുന്നു: "കഴിഞ്ഞ ഒരു മണിക്കൂറിലെ എല്ലാ ETH trades", "രണ്ട് timestamp-കൾക്കിടയിലുള്ള BTC trades", അല്ലെങ്കിൽ "ഓരോ symbol-ന്റെയും ഏറ്റവും പുതിയ trade". column order പ്രധാനമാണ് — symbol ആദ്യം equality filtering enable ചെയ്യുന്നു, എന്നിട്ട് executed_at index-ന്റെ ആ partition-നുള്ളിൽ efficient range scan-കൾ enable ചെയ്യുന്നു.
ഹൺഡ്രഡ്സ് ഓഫ് മില്യൺസ് rows-നപ്പുറം വളരുന്ന table-കൾക്ക്, table partitioning അത്യാവശ്യമാണ്. PostgreSQL range അനുസരിച്ച് declarative partitioning support ചെയ്യുന്നു — time-series-ന് perfect:
CREATE TABLE trades (
trade_id BIGINT, symbol VARCHAR(20),
price NUMERIC(18,8), executed_at TIMESTAMPTZ
) PARTITION BY RANGE (executed_at);
CREATE TABLE trades_2026_q1 PARTITION OF trades
FOR VALUES FROM ('2026-01-01') TO ('2026-04-01');
CREATE TABLE trades_2026_q2 PARTITION OF trades
FOR VALUES FROM ('2026-04-01') TO ('2026-07-01');
Partitioning-ഓടെ, 2026 മാർച്ചിലെ ഡാറ്റയ്ക്കുള്ള ഒരു query Q1 partition മാത്രമേ scan ചെയ്യൂ — engine Q2, Q3, Q4 പൂർണ്ണമായി skip ചെയ്യുന്നു. Partition pruning എന്ന് വിളിക്കുന്ന ഈ technique, വലിയ historical ഡാറ്റാസെറ്റുകളിൽ order-of-magnitude speedup-കൾ ഡെലിവർ ചെയ്യുന്നു.
PostgreSQL vs ClickHouse vs BigQuery: ശരിയായ Engine തിരഞ്ഞെടുക്കൽ
എല്ലാ database-കളും ഫിനാൻഷ്യൽ analytics ഒരുപോലെ handle ചെയ്യുന്നില്ല. തിരഞ്ഞെടുപ്പ് നിങ്ങളുടെ query pattern-കൾ, ഡാറ്റ volume, latency requirements എന്നിവയെ ആശ്രയിക്കുന്നു.
PostgreSQL ആണ് workhorse. ഇത് transactional workload-കളിൽ (real time-ൽ trades record ചെയ്യുന്നത്) excel ചെയ്യുന്നു, ACID guarantee-കൾ support ചെയ്യുന്നു, സങ്കീർണ്ണമായ JOIN-കൾ gracefully handle ചെയ്യുന്നു, ശരിയായ indexing, partitioning-ഓടെ ഹൺഡ്രഡ്സ് ഓഫ് മില്യൺസ് rows-ലേക്ക് സ്കെയിൽ ചെയ്യുന്നു. operational database-കൾക്ക് — system of record-ന് — ഇത് ശരിയായ തിരഞ്ഞെടുപ്പാണ്. ഉദാഹരണത്തിന് GaiaEx, ഫിനാൻഷ്യൽ സിസ്റ്റങ്ങൾ ആവശ്യപ്പെടുന്ന reliability guarantee-കളോടെ അതിന്റെ core trading data-ക്ക് PostgreSQL-compatible ഇൻഫ്രാസ്ട്രക്ചർ ആശ്രയിക്കുന്നു.
ClickHouse ബില്യൺ കണക്കിന് rows-ൽ analytical query-കൾക്കായി ഡിസൈൻ ചെയ്ത ഒരു columnar database ആണ്. PostgreSQL row by row ഡാറ്റ സ്റ്റോർ ചെയ്യുന്നിടത്ത് (individual trades insert ചെയ്യാൻ മികച്ചത്), ClickHouse column by column ഡാറ്റ സ്റ്റോർ ചെയ്യുന്നു (ദശലക്ഷക്കണക്കിന് rows-ലുടനീളം ഒരു single column aggregate ചെയ്യാൻ മികച്ചത്). "3 വർഷത്തിനുള്ളിൽ BTC-യുടെ average hourly volume" പോലുള്ള ഒരു query PostgreSQL-ൽ 30 സെക്കൻഡ് എടുക്കുന്നത് ClickHouse-ൽ 200 മില്ലിസെക്കൻഡിൽ പൂർത്തിയാകാം. trade-off: ClickHouse UPDATE-യോ DELETE-യോ efficiently support ചെയ്യുന്നില്ല — ഇത് ഡിസൈൻ പ്രകാരം append-only ആണ്.
BigQuery (Google Cloud) ഒരു serverless columnar warehouse ആണ്. Manage ചെയ്യേണ്ട ഇൻഫ്രാസ്ട്രക്ചർ ഇല്ല, pay-per-query pricing, petabyte-scale capacity. ad-hoc analytics, research, exploration എന്നിവയ്ക്ക് ideal ആണ് — പക്ഷേ query latency സെക്കൻഡുകളിലാണ് അളക്കുന്നത്, മില്ലിസെക്കൻഡിലല്ല, real-time applications-ന് ഇത് unsuitable ആക്കുന്നു.
- Real-time trade recording, order management → PostgreSQL
- ബില്യൺ കണക്കിന് rows-ലുടനീളമുള്ള historical analytics, backtesting → ClickHouse
- Ad-hoc exploration, cross-team data sharing → BigQuery
പല professional trading firm-കളും ഒരു tiered architecture-ൽ മൂന്നും ഉപയോഗിക്കുന്നു: hot operational store ആയി PostgreSQL, warm analytical layer ആയി ClickHouse, cold archive ആയി BigQuery. നല്ല SQL എഴുതുന്ന skill ഇവയിലുടനീളം transfer ചെയ്യുന്നു — syntax 90% identical ആണ്, analytical thinking 100% ഒരേപോലെയാണ്.