-- Create standard table firstCREATE TABLE crypto_scout.bybit_spot_kline_1m (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
openDOUBLE PRECISIONNOT NULL,
high DOUBLE PRECISIONNOT NULL,
low DOUBLE PRECISIONNOT NULL,
closeDOUBLE PRECISIONNOT NULL,
volume DOUBLE PRECISIONNOT NULL,
turnover DOUBLE PRECISIONNOT NULL,
PRIMARY KEY (time, symbol)
);
-- Convert to hypertableSELECT create_hypertable('crypto_scout.bybit_spot_kline_1m', 'time');
Table Definitions
Kline Tables (Candlestick Data)
CREATE TABLE crypto_scout.bybit_spot_kline_1m (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
openDOUBLE PRECISIONNOT NULL,
high DOUBLE PRECISIONNOT NULL,
low DOUBLE PRECISIONNOT NULL,
closeDOUBLE PRECISIONNOT NULL,
volume DOUBLE PRECISIONNOT NULL,
turnover DOUBLE PRECISIONNOT NULL,
PRIMARY KEY (time, symbol)
);
-- Indexes for common queriesCREATE INDEX idx_bybit_spot_kline_1m_symbol_time
ON crypto_scout.bybit_spot_kline_1m (symbol, timeDESC);
Ticker Tables
CREATE TABLE crypto_scout.bybit_spot_tickers (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
last_price DOUBLE PRECISIONNOT NULL,
high_price_24h DOUBLE PRECISIONNOT NULL,
low_price_24h DOUBLE PRECISIONNOT NULL,
volume_24h DOUBLE PRECISIONNOT NULL,
turnover_24h DOUBLE PRECISIONNOT NULL,
PRIMARY KEY (time, symbol)
);
SELECT create_hypertable('crypto_scout.bybit_spot_tickers', 'time');
Trade Tables
CREATE TABLE crypto_scout.bybit_spot_public_trade (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
trade_id TEXT NOT NULL,
price DOUBLE PRECISIONNOT NULL,
qty DOUBLE PRECISIONNOT NULL,
side TEXT NOT NULL,
PRIMARY KEY (time, trade_id)
);
SELECT create_hypertable('crypto_scout.bybit_spot_public_trade', 'time');
Order Book Tables
CREATE TABLE crypto_scout.bybit_spot_order_book_200 (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
side TEXT NOT NULL, -- 'bid' or 'ask'
price DOUBLE PRECISIONNOT NULL,
qty DOUBLE PRECISIONNOT NULL,
PRIMARY KEY (time, symbol, side, price)
);
SELECT create_hypertable('crypto_scout.bybit_spot_order_book_200', 'time');
Liquidation Table (Linear only)
CREATE TABLE crypto_scout.bybit_linear_all_liquidation (
time TIMESTAMPTZ NOT NULL,
symbol TEXT NOT NULL,
side TEXT NOT NULL,
price DOUBLE PRECISIONNOT NULL,
qty DOUBLE PRECISIONNOT NULL,
PRIMARY KEY (time, symbol, side, price)
);
SELECT create_hypertable('crypto_scout.bybit_linear_all_liquidation', 'time');
publicvoidsaveWithOffset(
final List<Data> data,
final String streamName,
finallong offset
)throws SQLException {
finalvarinsertSql="INSERT INTO ...";
finalvaroffsetSql="INSERT INTO crypto_scout.stream_offsets (stream_name, offset_value) " +
"VALUES (?, ?) " +
"ON CONFLICT (stream_name) DO UPDATE SET offset_value = EXCLUDED.offset_value";
try (finalvarconn= dataSource.getConnection()) {
conn.setAutoCommit(false);
try {
// Insert datatry (finalvarstmt= conn.prepareStatement(insertSql)) {
for (finalvar d : data) {
// set parameters
stmt.addBatch();
}
stmt.executeBatch();
}
// Update offsettry (finalvarstmt= conn.prepareStatement(offsetSql)) {
stmt.setString(1, streamName);
stmt.setLong(2, offset);
stmt.executeUpdate();
}
conn.commit();
} catch (SQLException e) {
conn.rollback();
throw e;
}
}
}
Query Patterns
Time-Range Queries
-- Get klines for last 24 hoursSELECT*FROM crypto_scout.bybit_spot_kline_1m
WHERE symbol ='BTCUSDT'ANDtime>= NOW() -INTERVAL'24 hours'ORDERBYtimeDESC;
-- Get aggregated daily dataSELECT
time_bucket('1 day', time) ASday,
symbol,
first(open, time) ASopen,
max(high) AS high,
min(low) AS low,
last(close, time) ASclose,
sum(volume) AS volume
FROM crypto_scout.bybit_spot_kline_1m
WHERE symbol ='BTCUSDT'GROUPBYday, symbol
ORDERBYdayDESC;
Continuous Aggregates
-- Create 1-hour continuous aggregateCREATE MATERIALIZED VIEW crypto_scout.bybit_spot_kline_1h
WITH (timescaledb.continuous) ASSELECT
time_bucket('1 hour', time) AS bucket,
symbol,
first(open, time) ASopen,
max(high) AS high,
min(low) AS low,
last(close, time) ASclose,
sum(volume) AS volume,
sum(turnover) AS turnover
FROM crypto_scout.bybit_spot_kline_1m
GROUPBY bucket, symbol;
-- Refresh policySELECT add_continuous_aggregate_policy(
'crypto_scout.bybit_spot_kline_1h',
start_offset =>INTERVAL'1 month',
end_offset =>INTERVAL'1 hour',
schedule_interval =>INTERVAL'1 hour'
);
Latest Data Queries
-- Get latest ticker for each symbolSELECTDISTINCTON (symbol)
symbol,
last_price,
timeFROM crypto_scout.bybit_spot_tickers
ORDERBY symbol, timeDESC;
-- Get data for specific time rangeSELECT*FROM crypto_scout.cmc_fgi
WHEREtime>='2024-01-01'ANDtime<'2024-02-01'ORDERBYtime;
# Using pg_dump
pg_dump -h localhost -p 5432 -U crypto_scout_db -d crypto_scout > backup.sql
# Using backup sidecar (configured in compose)# Backups are written to ./backups automatically
Restore
# From SQL file
psql -h localhost -p 5432 -U crypto_scout_db -d crypto_scout < backup.sql
# From custom format
pg_restore -h localhost -p 5432 -U crypto_scout_db -d crypto_scout backup.dump