# -*- coding: utf-8 -*-
"""XUAT_SO_LIEU.PY — chạy trên api1: gói số liệu thị trường cho BẢN TIN (02/10/2026). CHỈ ĐỌC.

Chủ dự án: bản tin vàng buổi sáng (phần A) dựa trên dữ liệu RIÊNG của hệ thống — nến XAUUSD (market.ohlcv, Postgres
superdata) và trạng thái thị trường (REGIME_DAILY trong matching.db của pipeline perday). Máy web không có Postgres,
nên api1 xuất gói JSON; máy web phân tích, vẽ, viết, phát (private/services/chatbot/ban_tin/).

Bản 2 (02/10, "lấy cả 11 phần, có thêm liên thị trường"):
  - vàng D1 / H4 / H1 đủ dài cho EMA200, ATR bách phân vị, đỉnh đáy sóng;
  - USDX (EA FeederPhu, sàn Vantage) D1 / H1; lợi suất trái phiếu Mỹ 10 năm (Bộ Tài chính Mỹ, CSV theo năm);
  - lịch tin MT5 (EA FeederPhu -> data/lich_tin.db, giờ UTC) + PHẢN ỨNG CỦA VÀNG ở các lần ra tin trước (2 nến H1
    tính từ giờ ra tin: biên độ, hướng), để bản tin nói "tin này các lần trước làm vàng chạy bao nhiêu".

Giờ trong market.ohlcv là GIỜ SÀN (EET/EEST: UTC+2 mùa đông, UTC+3 mùa hè) — giữ nguyên, bên web tự đổi.

Dùng:  /root/venv/bin/python xuat_so_lieu.py [--tu-d1 2025-08-01] [--tu-lich 2026-09-10] > goi.json
"""
from __future__ import annotations

import argparse
import csv
import io
import json
import os
import sqlite3
import sys
import urllib.request
from datetime import date, datetime, timedelta, timezone

GOC = '/root/systemai'
DATA = os.path.join(GOC, 'dca/phan tich so lieu/data')
MATCHING = os.path.join(DATA, 'optimization/matching.db')
LICH_DB = os.path.join(DATA, 'lich_tin.db')
TRANG_THAI = os.path.join(GOC, 'dca/phan tich so lieu/dashboard/static/daily_status.json')
MA = 'XAUUSD_pc'
MA_USDX = 'USDX'
# tin mức 2 của MT5 nhưng vàng phản ứng mạnh -> cũng tính phản ứng (mức 3 thì luôn tính)
MA_THEM = ('fomc-meeting-statement', 'fomc-minutes', 'fomc-economic-projections', 'michigan-consumer-sentiment',
           'producer-price-index-ex-food-energy-mm')
URL_LOI_SUAT = ('https://home.treasury.gov/resource-center/data-chart-center/interest-rates/daily-treasury-rates.csv/'
                '{nam}/all?type=daily_treasury_yield_curve&field_tdr_date_value={nam}&page&_format=csv')


def _pgurl() -> str:
    url = os.environ.get('PGURL', '')
    if not url:
        for ln in open(os.path.join(GOC, '.env'), encoding='utf-8'):
            if ln.startswith('PGURL='):
                url = ln.split('=', 1)[1].strip()
    return url


def _chu_nhat_cuoi(nam: int, thang: int) -> date:
    d = date(nam, thang + 1, 1) - timedelta(days=1)
    return d - timedelta(days=(d.weekday() + 1) % 7)


def lech_san(t_utc: datetime) -> int:
    """Giờ sàn = UTC+3 từ CN cuối tháng 3 (01:00 UTC) tới CN cuối tháng 10, còn lại UTC+2 (khớp ban_tin/phan_tich.py)."""
    bd = datetime.combine(_chu_nhat_cuoi(t_utc.year, 3), datetime.min.time()) + timedelta(hours=1)
    kt = datetime.combine(_chu_nhat_cuoi(t_utc.year, 10), datetime.min.time()) + timedelta(hours=1)
    return 3 if bd <= t_utc < kt else 2


def _nen(cur, ma: str, tf: str, tu: str) -> list:
    cur.execute('SELECT ts, open, high, low, close FROM market.ohlcv WHERE symbol = %s AND tf = %s AND ts >= %s ORDER BY ts',
                (ma, tf, tu))
    return [[r[0].strftime('%Y-%m-%d %H:%M'), float(r[1]), float(r[2]), float(r[3]), float(r[4])] for r in cur.fetchall()]


def loi_suat_10n(nam_ds) -> list:
    """[[yyyy-mm-dd, %], …] tăng dần. Lỗi mạng -> danh sách rỗng (bản tin tự bỏ phần lợi suất)."""
    ra = {}
    for nam in nam_ds:
        try:
            rq = urllib.request.Request(URL_LOI_SUAT.format(nam=nam), headers={'User-Agent': 'TradingAuto ban tin'})
            van_ban = urllib.request.urlopen(rq, timeout=20).read().decode('utf-8-sig')
        except Exception:  # noqa: BLE001
            continue
        for d in csv.DictReader(io.StringIO(van_ban)):
            try:
                ngay = datetime.strptime(d['Date'], '%m/%d/%Y').date().isoformat()
                ra[ngay] = float(d['10 Yr'])
            except (KeyError, ValueError):
                continue
    return [[k, ra[k]] for k in sorted(ra)]


def _phan_ung(h1_ds: dict, t_utc: datetime):
    """Hai nến H1 vàng tính từ giờ ra tin (giờ sàn): (biên độ cao-thấp, hướng đóng-mở). Thiếu nến -> None."""
    t = t_utc + timedelta(hours=lech_san(t_utc))
    a = t.replace(minute=0, second=0, microsecond=0)
    n1, n2 = h1_ds.get(a.strftime('%Y-%m-%d %H:%M')), h1_ds.get((a + timedelta(hours=1)).strftime('%Y-%m-%d %H:%M'))
    if not n1 or not n2:
        return None
    return round(max(n1[2], n2[2]) - min(n1[3], n2[3]), 2), round(n2[4] - n1[1], 2)


def lich(cur, tu_lich: str, den: str) -> tuple:
    """(lịch USD mức >= 2 trong [tu_lich, den), phản ứng của vàng ở các lần trước của tin mức 3 / MA_THEM trong khoảng đó)."""
    if not os.path.isfile(LICH_DB):
        return [], {}
    m = sqlite3.connect(f'file:{LICH_DB}?mode=ro', uri=True)
    cot = ('id', 'eid', 'ma', 'ten', 'muc', 't_utc', 'thuc_te', 'du_bao', 'truoc', 'truoc_sua', 'don_vi')
    ds = [dict(zip(cot, r)) for r in m.execute(
        f"SELECT {', '.join(cot)} FROM lich_tin WHERE tien_te = 'USD' AND muc >= 2 AND t_utc >= ? AND t_utc < ? "
        'ORDER BY t_utc, id', (tu_lich, den))]
    eids = sorted({x['eid'] for x in ds if x['muc'] == 3 or x['ma'] in MA_THEM})
    phan_ung = {}
    if eids:
        qua = [dict(zip(cot, r)) for r in m.execute(
            f"SELECT {', '.join(cot)} FROM lich_tin WHERE eid IN ({','.join('?' * len(eids))}) AND t_utc < ? ORDER BY t_utc",
            (*eids, den))]
        tu = min((x['t_utc'] for x in qua), default=den)[:10]
        h1 = {b[0]: b for b in _nen(cur, MA, 'H1', tu)}
        for x in qua:
            t = datetime.strptime(x['t_utc'], '%Y-%m-%d %H:%M:%S')
            p = _phan_ung(h1, t)
            if p:
                phan_ung.setdefault(str(x['eid']), []).append([x['t_utc'], x['thuc_te'], x['du_bao'], p[0], p[1]])
    m.close()
    return ds, phan_ung


def xuat(tu_d1: str, tu_h4: str, tu_h1: str, tu_regime: str, tu_lich: str) -> dict:
    import psycopg2
    cn = psycopg2.connect(_pgurl(), connect_timeout=10)
    cur = cn.cursor()
    ra = {'ma': MA, 'gio': 'san', 'phien_ban': 2}
    for tf, tu in (('D1', tu_d1), ('H4', tu_h4), ('H1', tu_h1)):
        ra[tf.lower()] = _nen(cur, MA, tf, tu)
    ra['usdx'] = {'d1': _nen(cur, MA_USDX, 'D1', tu_d1), 'h1': _nen(cur, MA_USDX, 'H1', tu_h1)}
    den = (datetime.now(timezone.utc).replace(tzinfo=None) + timedelta(days=40)).strftime('%Y-%m-%d')   # lịch cả tháng tới (bài tầm nhìn tháng)
    ra['lich'], ra['phan_ung_tin'] = lich(cur, tu_lich, den)
    cn.close()
    ra['us10y'] = loi_suat_10n(range(int(tu_d1[:4]), date.today().year + 1))
    m = sqlite3.connect(f'file:{MATCHING}?mode=ro', uri=True)
    cot = ('date', 'regime', 'hmm_state', 'adx', 'atr_pct', 'rsi', 'bb_width', 'sma_slope', 'price_vs_sma')
    ra['regime'] = [dict(zip(cot, r)) for r in m.execute(
        f'SELECT {", ".join(cot)} FROM REGIME_DAILY WHERE date >= ? ORDER BY date', (tu_regime,))]
    try:
        d = json.load(open(TRANG_THAI, encoding='utf-8'))
        t = d.get('transition') or {}
        ra['trang_thai_moi'] = {'date': d.get('date'), 'regime': d.get('regime'), 'c_label': d.get('c_label'),
                                'chuyen': {k: t.get(k) for k in ('date', 'from_regime', 'to_regime', 'fresh', 'days_since')}}
    except Exception as e:  # noqa: BLE001
        ra['trang_thai_moi'] = {'loi': str(e)[:200]}
    return ra


if __name__ == '__main__':
    p = argparse.ArgumentParser()
    hom_nay = date.today()
    p.add_argument('--tu-d1', default=str(hom_nay - timedelta(days=1100)))   # ~3 năm: nến tháng / tuần
    p.add_argument('--tu-h4', default=str(hom_nay - timedelta(days=75)))
    p.add_argument('--tu-h1', default=str(hom_nay - timedelta(days=45)))     # tự chấm cả tháng trước
    p.add_argument('--tu-regime', default=str(hom_nay - timedelta(days=45)))
    p.add_argument('--tu-lich', default=str(hom_nay - timedelta(days=45)))
    a = p.parse_args()
    json.dump(xuat(a.tu_d1, a.tu_h4, a.tu_h1, a.tu_regime, a.tu_lich), sys.stdout, ensure_ascii=False)
