#03-基金分析查询
基金净值、持仓、跟踪误差查询。支撑基金标的研究与实盘操作。
#基金基本信息
SELECT fund_code, fund_name, fund_type, tracking_index,
management_company, manager, management_fee, custody_fee,
inception_date
FROM dim_fund
WHERE fund_code = '510300';按跟踪指数筛选基金:
SELECT f.fund_code, f.fund_name, f.fund_type, f.management_fee + f.custody_fee AS total_fee
FROM dim_fund f
WHERE f.tracking_index = '000300'
AND f.fund_type IN ('ETF', '场外指数')
ORDER BY total_fee ASC;同一跟踪指数的多只基金,优先选费率低的。
#基金净值与行情
#ETF 日线
from db import get_connection
from query_utils import query_to_df, quality_filter
conn = get_connection()
df = query_to_df(conn, f"""
SELECT trade_date, open, close, high, low, volume, amount, pct_change
FROM fund_daily
WHERE fund_code = ?
AND trade_date >= date('now', '-1 year')
AND {quality_filter()}
ORDER BY trade_date
""", ("510300",))#场外基金净值
SELECT trade_date, unit_nav, accum_nav, pct_change
FROM fund_daily
WHERE fund_code = '110011'
AND data_quality IN ('ok', 'manual_fixed')
ORDER BY trade_date DESC
LIMIT 30;#累计收益率计算
df["daily_return"] = df["close"].pct_change()
df["cum_return"] = (1 + df["daily_return"]).cumprod() - 1#基金持仓查询
#最新持仓
SELECT stock_code, stock_name, hold_ratio, hold_value, rank
FROM fund_holdings
WHERE fund_code = '510300'
AND report_date = (SELECT MAX(report_date) FROM fund_holdings WHERE fund_code = '510300')
ORDER BY rank;#持仓变化(对比上期)
WITH latest AS (
SELECT stock_code, stock_name, hold_ratio, rank
FROM fund_holdings
WHERE fund_code = '510300'
AND report_date = (SELECT MAX(report_date) FROM fund_holdings WHERE fund_code = '510300')
),
prev AS (
SELECT stock_code, stock_name, hold_ratio, rank
FROM fund_holdings
WHERE fund_code = '510300'
AND report_date = (
SELECT MAX(report_date) FROM fund_holdings
WHERE fund_code = '510300'
AND report_date < (SELECT MAX(report_date) FROM fund_holdings WHERE fund_code = '510300')
)
)
SELECT
COALESCE(l.stock_code, p.stock_code) AS stock_code,
COALESCE(l.stock_name, p.stock_name) AS stock_name,
p.hold_ratio AS prev_ratio,
l.hold_ratio AS latest_ratio,
l.hold_ratio - p.hold_ratio AS ratio_change
FROM latest l
FULL OUTER JOIN prev p ON l.stock_code = p.stock_code
ORDER BY ABS(l.hold_ratio - p.hold_ratio) DESC NULLS LAST;注意 SQLite 较老版本不支持 FULL OUTER JOIN,可用 LEFT JOIN + UNION 替代。
#反向查询:哪些基金持有某股票
SELECT f.fund_code, f.fund_name, h.report_date, h.hold_ratio, h.rank
FROM fund_holdings h
JOIN dim_fund f ON h.fund_code = f.fund_code
WHERE h.stock_code = '600519'
AND h.report_date >= date('now', '-1 year')
ORDER BY h.report_date DESC, h.hold_ratio DESC;用于分析某只股票被哪些基金重仓,辅助判断个股的行业代表性。
#跟踪误差分析
指数基金与跟踪指数的偏离度:
WITH fund_returns AS (
SELECT trade_date, pct_change AS fund_ret
FROM fund_daily
WHERE fund_code = '510300' AND data_quality IN ('ok', 'manual_fixed')
),
index_returns AS (
SELECT trade_date, pct_change AS index_ret
FROM index_daily
WHERE index_code = '000300' AND data_quality IN ('ok', 'manual_fixed')
)
SELECT
AVG(f.fund_ret - i.index_ret) AS mean_tracking_error,
-- 跟踪误差标准差(年化)
SQRT(AVG((f.fund_ret - i.index_ret) * (f.fund_ret - i.index_ret))) * SQRT(250) AS annual_te
FROM fund_returns f
JOIN index_returns i ON f.trade_date = i.trade_date;年化跟踪误差 < 1% 为优秀,1-2% 为良好,> 2% 需关注。
#多基金对比
SELECT
f.fund_code, f.fund_name,
MAX(CASE WHEN d.trade_date = (SELECT MAX(trade_date) FROM fund_daily) THEN d.close END) AS latest_close,
COUNT(*) AS days,
MIN(d.close) AS min_close,
MAX(d.close) AS max_close
FROM dim_fund f
JOIN fund_daily d ON f.fund_code = d.fund_code
WHERE f.fund_code IN ('510300', '510500', '159915', '588000')
AND d.data_quality IN ('ok', 'manual_fixed')
GROUP BY f.fund_code, f.fund_name;#封装函数建议
def get_fund_info(conn, fund_code: str) -> pd.DataFrame:
"""基金基本信息。"""
def get_fund_nav_history(conn, fund_code: str, years: int = 3) -> pd.DataFrame:
"""基金净值历史。"""
def get_fund_holdings_latest(conn, fund_code: str) -> pd.DataFrame:
"""基金最新持仓。"""
def get_funds_holding_stock(conn, stock_code: str) -> pd.DataFrame:
"""反向查询:哪些基金持有某股票。"""
def calc_tracking_error(conn, fund_code: str, index_code: str) -> float:
"""计算年化跟踪误差。"""