File Parsing · General · Practice Question
Find Exchanges Supporting a Trading Pair
Question
A reference data file contains exchange and trading-pair records, one record per row.
Each row is written in the format:
Exchange_Base-QuoteExample symex.txt:
Binance_BTC-USDT
Coinbase_ETH-USD
Kraken_BTC-USD
OKX_SOL-USDT
Bybit_BTC-USDC
Bitstamp_XRP-USD
Binance_ETH-USDT
Coinbase_BTC-USDC
Kraken_DOT-USDWrite a q expression to return all exchanges where the trading pair BTC-USDC is supported.
Solution
t:flip ([ex:;asset:]) . flip "_" vs/: read0 `:symex.txt
exec ex from t where asset like "BTC-USDC"Result:
"Bybit"
"Coinbase"Alternative Solution
a:flip "_" vs/: read0 `:symex.txt
a[0] where a[1] like "BTC-USDC"Result:
"Bybit"
"Coinbase"Explanation
First, read the file:
read0 `:symex.txtThis returns a list of strings:
"Binance_BTC-USDT"
"Coinbase_ETH-USD"
"Kraken_BTC-USD"
"OKX_SOL-USDT"
"Bybit_BTC-USDC"
"Bitstamp_XRP-USD"
"Binance_ETH-USDT"
"Coinbase_BTC-USDC"
"Kraken_DOT-USD"Next, split each row on the underscore character:
"_" vs/: read0 `:symex.txtResult:
"Binance" "BTC-USDT"
"Coinbase" "ETH-USD"
"Kraken" "BTC-USD"
"OKX" "SOL-USDT"
"Bybit" "BTC-USDC"
"Bitstamp" "XRP-USD"
"Binance" "ETH-USDT"
"Coinbase" "BTC-USDC"
"Kraken" "DOT-USD"The solution then transposes the nested list:
flip "_" vs/: read0 `:symex.txtResult:
"Binance" "Coinbase" "Kraken" "OKX" "Bybit" "Bitstamp" "Binance" "Coinbase" "Kraken"
"BTC-USDT" "ETH-USD" "BTC-USD" "SOL-USDT" "BTC-USDC" "XRP-USD" "ETH-USDT" "BTC-USDC" "DOT-USD"The first row now contains all exchanges and the second row contains all trading pairs.
The dictionary literal syntax introduced in kdb+ 4.1 allows us to define a dictionary projection:
([ex:;asset:])This projection expects two values:
- One for the
exkey - One for the
assetkey
Applying the projection to the flipped data:
([ex:;asset:]) . flip "_" vs/: read0 `:symex.txtcreates a dictionary:
ex | "Binance" "Coinbase" "Kraken" "OKX" "Bybit" "Bitstamp" "Binance" "Coinbase" "Kraken"
asset| "BTC-USDT" "ETH-USD" "BTC-USD" "SOL-USDT" "BTC-USDC" "XRP-USD" "ETH-USDT" "BTC-USDC" "DOT-USD"This is known as a column dictionary because each key contains an entire column of values.
Finally, flip converts the column dictionary into a table:
flip ([ex:;asset:]) . flip "_" vs/: read0 `:symex.txtResult:
ex asset
---------------------
"Binance" "BTC-USDT"
"Coinbase" "ETH-USD"
"Kraken" "BTC-USD"
"OKX" "SOL-USDT"
"Bybit" "BTC-USDC"
"Bitstamp" "XRP-USD"
"Binance" "ETH-USDT"
"Coinbase" "BTC-USDC"
"Kraken" "DOT-USD"The table is assigned to t:
t:flip ([ex:;asset:]) . flip "_" vs/: read0 `:symex.txtOnce the data is in tabular form, we can query it using standard q syntax:
exec ex from t where asset like "BTC-USDC"This filters the rows where the asset column equals BTC-USDC and returns:
"Bybit"
"Coinbase"Alternative Solution
The alternative solution avoids creating a table entirely:
a:flip "_" vs/: read0 `:symex.txtAfter the flip:
a[0]contains the exchanges:
"Binance"
"Coinbase"
"Kraken"
"OKX"
"Bybit"
"Bitstamp"
"Binance"
"Coinbase"
"Kraken"and:
a[1]contains the trading pairs:
"BTC-USDT"
"ETH-USD"
"BTC-USD"
"SOL-USDT"
"BTC-USDC"
"XRP-USD"
"ETH-USDT"
"BTC-USDC"
"DOT-USD"The expression:
a[1] like "BTC-USDC"returns a boolean vector identifying the matching rows (like takes the list of strings on the left and the pattern on the right). With no wildcards in the pattern, this is an exact match; a[1] ~\: "BTC-USDC" would give the same result.
Those positions are then used to select the corresponding exchanges:
a[0] where a[1] like "BTC-USDC"Result:
"Bybit"
"Coinbase"The main solution demonstrates how dictionary literal syntax can be used to quickly construct a table, while the alternative solution shows how the same task can be solved directly using list operations.