QMT持仓数据获取后,我是这样用Python做盈亏分析和风险监控的

每次收盘后盯着账户发呆的日子终于结束了。作为一名用量化策略交易的散户,我曾经也经历过手动计算每只股票盈亏、用Excel画饼图的阶段,直到发现QMT的API配合Python能实现全自动分析。现在只需要3分钟,系统就能生成带预警标记的完整报告,这才是数字时代交易者该有的效率。

1. 从原始数据到结构化DataFrame

拿到QMT的持仓数据只是第一步,真正的挑战在于如何把这些零散的信息变成可分析的结构化数据。我习惯用Pandas的DataFrame作为中间容器,这样后续所有操作都会变得异常简单。

import pandas as pd

def get_position_df(account):
    raw_data = get_trade_detail_data(account, 'stock', 'position')
    position_list = []
    
    for item in raw_data:
        position_list.append({
            'symbol': f"{item.m_strInstrumentID}.{item.m_strExchangeID}",
            'name': item.m_strInstrumentName,
            'volume': item.m_nVolume,
            'available': item.m_nCanUseVolume,
            'cost_price': item.m_dOpenPrice,
            'market_value': item.m_dInstrumentValue,
            'position_cost': item.m_dPositionCost,
            'profit': item.m_dPositionProfit
        })
    
    return pd.DataFrame(position_list)

这个转换函数会返回包含8个关键字段的DataFrame。我特别喜欢用 symbol 这个组合字段,它把股票代码和交易所信息合并成了类似 600519.SH 的标准格式,后续对接其他分析库时特别方便。

2. 给原始数据装上"计算引擎"

基础数据清洗完成后,就该上"硬菜"了——计算那些真正影响决策的衍生指标。我的计算清单通常包括:

  • 持仓占比 :单票市值/总市值
  • 盈亏比例 :盈亏金额/持仓成本
  • 累计收益率 :组合整体收益
  • 风险敞口 :行业/板块集中度
def enrich_position_data(df):
    # 计算总市值作为基准
    total_value = df['market_value'].sum()
    
    # 添加衍生字段
    df['weight'] = df['market_value'] / total_value
    df['profit_ratio'] = df['profit'] / df['position_cost']
    df['cost_basis'] = df['position_cost'] / df['volume']
    
    # 添加涨跌标志便于后续可视化
    df['is_profit'] = df['profit'] >= 0
    
    return df.sort_values('weight', ascending=False)

这里有个实用技巧:计算完权重后按降序排列,这样在后续可视化时,重要持仓会自动排在前面。我还特意加了 is_profit 这个布尔字段,等会儿画图时就知道为什么了。

3. 让数据自己"说话"的可视化技巧

枯燥的数字表格没人爱看,我摸索出一套固定可视化组合拳:

持仓分布图 用环形图呈现,中间空白处显示总收益率; 盈亏分析 用分组柱状图,红色绿色区分盈亏;再加上一个 风险预警看板 ,三图组合基本覆盖了所有分析需求。

import matplotlib.pyplot as plt

def plot_position_analysis(df, total_profit):
    plt.figure(figsize=(15, 5))
    
    # 持仓分布环形图
    plt.subplot(131)
    plt.pie(df['weight'], labels=df['symbol'], 
            wedgeprops={'width':0.3}, autopct='%1.1f%%')
    plt.title('持仓分布')
    
    # 盈亏柱状图
    plt.subplot(132)
    colors = ['green' if x else 'red' for x in df['is_profit']]
    plt.bar(df['symbol'], df['profit'], color=colors)
    plt.xticks(rotation=45)
    plt.title('单票盈亏')
    
    # 文本摘要
    plt.subplot(133)
    plt.axis('off')
    summary_text = f"总收益率: {total_profit:.2%}\n"
    summary_text += f"持仓数量: {len(df)}\n"
    summary_text += f"盈利标的: {df['is_profit'].sum()}"
    plt.text(0.1, 0.5, summary_text, fontsize=12)
    
    plt.tight_layout()
    return plt

这段代码生成的组合图表可以直接嵌入到日报邮件里。如果追求更炫酷的效果,可以把Matplotlib换成Plotly,但就日常使用而言,轻量级的Matplotlib完全够用。

4. 全天候运行的风险监控系统

单纯的事后分析还不够,我需要实时知道哪些持仓触发了预警规则。我的做法是构建一个可配置的预警引擎:

class RiskMonitor:
    def __init__(self):
        self.rules = {
            'single_loss': {'threshold': -0.1, 'active': True},
            'concentration': {'threshold': 0.3, 'active': True},
            'liquidity': {'threshold': 0.8, 'active': False}
        }
    
    def check_rules(self, position_df):
        alerts = []
        
        # 单票亏损预警
        if self.rules['single_loss']['active']:
            loss_stocks = position_df[
                position_df['profit_ratio'] <= self.rules['single_loss']['threshold']
            ]
            for _, row in loss_stocks.iterrows():
                alerts.append(f"亏损预警: {row['symbol']} 亏损达{row['profit_ratio']:.2%}")
        
        # 集中度预警
        if self.rules['concentration']['active']:
            top_holdings = position_df.head(2)
            if top_holdings['weight'].sum() > self.rules['concentration']['threshold']:
                alerts.append("集中度预警: 前两大持仓占比过高")
        
        return alerts

这个监控类最好的地方在于规则可配置。比如在行情波动大的时期,我会开启流动性检查;而在调仓阶段,则会临时调高集中度阈值。预警信息会通过企业微信机器人推送到手机,确保不错过任何风险信号。

5. 把这些组装成自动化流水线

最后一步是把所有组件串联起来,形成端到端的分析流水线。我习惯用Jupyter Notebook作为执行环境,但核心逻辑完全可以移植到定时任务中:

# 主执行流程
account = '您的资金账号'  # 实际使用需要替换

# 数据获取与加工
positions = get_position_df(account)
enriched_df = enrich_position_data(positions)
total_profit = enriched_df['profit'].sum() / enriched_df['position_cost'].sum()

# 可视化分析
chart = plot_position_analysis(enriched_df, total_profit)
chart.savefig('daily_report.png')

# 风险扫描
monitor = RiskMonitor()
alerts = monitor.check_rules(enriched_df)
if alerts:
    print("今日风险警报:")
    for alert in alerts:
        print(f"⚠️ {alert}")
else:
    print("✅ 今日无风险警报")

这套系统跑起来后,我每天收盘后要做的就是打开邮箱查收自动生成的报告,再瞄一眼手机确认没有风险警报。曾经需要半小时的手工分析,现在10秒就能获取更全面的洞见。

更多推荐