Add testing scripts for DB connection and candle reading

- test_db_connection.py: 5-stage DB connection test (TCP, auth, schema, data, db.py integration)
- read_candles.py: Read 1m candles with --all, --[symbol], --timestamp support
- README.md: Usage instructions for testing scripts
- .env.example: Template for connection configuration

Default symbols updated to match LiveCandleFetcher subscriptions (BNB, ETH, xyz:GOLD, etc.)
Colon-containing symbols handled via db.sanitize_table_name()
This commit is contained in:
DiTus
2026-08-05 20:33:54 +02:00
parent 1a95fe1caa
commit 7552cdfd57
4 changed files with 627 additions and 0 deletions

179
testing/read_candles.py Normal file
View File

@ -0,0 +1,179 @@
#!/usr/bin/env python3
"""
Candle Reader Test Script
Reads last 1m candles from PostgreSQL database on NAS.
Usage:
python testing/read_candles.py # Last candles for 12 default symbols
python testing/read_candles.py --all # Last candles for all symbols
python testing/read_candles.py --BTC # Last candles for BTC only
python testing/read_candles.py --BTC --ETH # Last candles for BTC and ETH
python testing/read_candles.py --xyz:GOLD # Last candles for xyz:GOLD only
python testing/read_candles.py --timestamp 05-08-26 # Nearest candle to Aug 5, 2026
python testing/read_candles.py --timestamp "05-08-26 13:30" # Nearest candle to Aug 5, 2026 13:30
python testing/read_candles.py --BTC --timestamp 05-08-26
Environment:
PG_HOST, PG_PORT, PG_DB, PG_USER, PG_PASSWORD, PG_TIMEOUT
(loaded from testing/.env)
"""
import os
import sys
import argparse
from datetime import datetime
try:
from dotenv import load_dotenv
_TESTING_DIR = os.path.dirname(os.path.abspath(__file__))
load_dotenv(os.path.join(_TESTING_DIR, ".env"))
except ImportError:
pass
_PROJECT_ROOT = os.path.dirname(_TESTING_DIR)
sys.path.insert(0, _PROJECT_ROOT)
import db
PG_HOST = os.environ.get("PG_HOST", "20.20.20.20")
PG_PORT = int(os.environ.get("PG_PORT", "5433"))
PG_DB = os.environ.get("PG_DB", "hyper")
PG_USER = os.environ.get("PG_USER", "hyper")
PG_PASSWORD = os.environ.get("PG_PASSWORD", "kaqpaaoi0")
db.PG_CONN_STR = f"postgresql://{PG_USER}:{PG_PASSWORD}@{PG_HOST}:{PG_PORT}/{PG_DB}"
DEFAULT_SYMBOLS = [
'BNB', 'ETH', 'xyz:GOLD', 'xyz:SILVER', 'SUI',
'xyz:BRENTOIL', 'mkts:USTECH', 'xyz:CL', 'xyz:XYZ100',
'HYPE', 'SOL', 'BTC'
]
def get_all_symbols(conn):
"""Get all 1m table names from the database."""
cur = conn.cursor()
cur.execute(
"""
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_type = 'BASE TABLE'
AND table_name LIKE '%_1m'
ORDER BY table_name
"""
)
tables = cur.fetchall()
cur.close()
symbols = []
for (table_name,) in tables:
symbol = table_name[:-3] if table_name.endswith('_1m') else table_name
symbols.append(symbol)
return symbols
def get_last_candle(conn, symbol):
"""Get the most recent 1m candle for a symbol."""
table = db.sanitize_table_name(symbol, '1m')
if not db.table_exists(conn, table):
return None
cur = conn.cursor()
cur.execute(f'SELECT * FROM "{table}" ORDER BY timestamp_ms DESC LIMIT 1')
row = cur.fetchone()
cur.close()
return row
def get_nearest_candle(conn, symbol, target_ts):
"""Get the candle nearest to the target timestamp."""
table = db.sanitize_table_name(symbol, '1m')
if not db.table_exists(conn, table):
return None
cur = conn.cursor()
cur.execute(
f'SELECT * FROM "{table}" ORDER BY ABS(timestamp_ms - %s) LIMIT 1',
(target_ts,)
)
row = cur.fetchone()
cur.close()
return row
def format_row(symbol, row):
"""Format a candle row for display."""
if row is None:
return f" {symbol:<15} | No data"
dt = row[0]
ts = row[1]
o = row[2]
h = row[3]
l = row[4]
c = row[5]
v = row[6]
return (
f" {symbol:<15} | "
f"{dt} | "
f"{ts} | "
f"O={o:.2f} H={h:.2f} L={l:.2f} C={c:.2f} | "
f"Vol={v:.2f}"
)
def main():
parser = argparse.ArgumentParser(
description="Read last 1m candles from PostgreSQL database on NAS."
)
parser.add_argument('--all', action='store_true',
help='List last candles for all symbols')
parser.add_argument('--timestamp', type=str, default=None,
help='DD-MM-YY or "DD-MM-YY HH:mm", list nearest candle to this date/time')
args, unknown = parser.parse_known_args()
symbols = []
for arg in unknown:
if arg.startswith('--'):
symbol = arg[2:]
symbols.append(symbol)
target_ts = None
if args.timestamp:
try:
if ' ' in args.timestamp:
dt = datetime.strptime(args.timestamp, '%d-%m-%y %H:%M')
else:
dt = datetime.strptime(args.timestamp, '%d-%m-%y')
target_ts = int(dt.timestamp() * 1000)
except ValueError:
print('Error: Invalid timestamp format. Use DD-MM-YY or "DD-MM-YY HH:mm" (e.g., 05-08-26 or "05-08-26 13:30")')
sys.exit(1)
conn = db.get_connection()
if args.all:
symbols = get_all_symbols(conn)
mode = "ALL symbols"
elif symbols:
mode = f"specified symbols: {', '.join(symbols)}"
else:
symbols = DEFAULT_SYMBOLS
mode = "default 12 symbols"
ts_str = f" (nearest to {args.timestamp})" if target_ts else ""
print(f"\n{'=' * 70}")
print(f"Last 1m Candles - {mode}{ts_str}")
print(f"{'=' * 70}")
for symbol in symbols:
if target_ts:
row = get_nearest_candle(conn, symbol, target_ts)
else:
row = get_last_candle(conn, symbol)
print(format_row(symbol, row))
print(f"{'=' * 70}\n")
conn.close()
if __name__ == "__main__":
main()