检测庄家试盘行为的量化策略 (C++11实现)

  • 时间:2025-11-19 19:59 作者: 来源: 阅读:0
  • 扫一扫,手机访问
摘要:#集合竞价主力试盘都有哪些手法##股票财经##量化#策略直接输出三种结论:出货试盘、拉升试盘或无试盘。代码基于XTP接口实现,包含了详细的注释。#include <iostream> #include <vector> #include <deque> #include <unordered_map> #include <cmath>

#集合竞价主力试盘都有哪些手法##股票财经##量化#

检测庄家试盘行为的量化策略 (C++11实现)

策略直接输出三种结论:出货试盘、拉升试盘或无试盘。
代码基于XTP接口实现,包含了详细的注释。


#include <iostream>
#include <vector>
#include <deque>
#include <unordered_map>
#include <cmath>
#include <algorithm>
#include <chrono>
#include <xtp_api_struct.h>
#include <xtp_quote_api.h>

// 命名空间简化
using namespace std;
using namespace std::chrono;

// 常量定义
const double PRICE_CHANGE_THRESHOLD = 0.015;      // 1.5%价格变动阈值
const double VOLUME_RATIO_THRESHOLD = 3.0;        // 成交量比率阈值
const double RECOVERY_THRESHOLD = 0.7;            // 价格恢复阈值
const double SHADOW_RATIO_THRESHOLD = 0.3;        // 影线比例阈值
const int TIME_WINDOW_SECONDS = 30;               // 分析时间窗口(秒)
const int VOLUME_ANALYSIS_WINDOW = 10;            // 成交量分析窗口(数据点)
const double TEST_PROBABILITY_THRESHOLD = 0.65;   // 试盘概率阈值

// 试盘类型枚举
enum TestType {
    NO_TEST,          // 无试盘
    UPWARD_TEST,      // 拉升试盘
    DOWNWARD_TEST,    // 出货试盘
    AMBIGUOUS_TEST    // 模棱两可的情况
};

// 股票数据结构
struct StockData {
    string ticker;                          // 股票代码
    double last_price;                      // 最新价格
    double pre_close;                       // 前收盘价
    double bid_prices[5];                   // 买1-买5价格
    double ask_prices[5];                   // 卖1-卖5价格
    int64_t bid_volumes[5];                 // 买1-买5量
    int64_t ask_volumes[5];                 // 卖1-卖5量
    int64_t volume;                         // 成交量
    int64_t turnover;                       // 成交额
    high_resolution_clock::time_point timestamp; // 时间戳
    
    // 存储历史K线数据用于分析
    deque<double> price_history;            // 价格历史
    deque<int64_t> volume_history;          // 成交量历史
    deque<double> price_changes;            // 价格变动历史
};

// 试盘检测结果
struct TestDetectionResult {
    TestType test_type = NO_TEST;           // 试盘类型
    double upward_prob = 0.0;               // 拉升试盘概率
    double downward_prob = 0.0;             // 出货试盘概率
    vector<string> indicators;              // 触发的指标
};

// 市场数据分析器
class MarketAnalyzer {
private:
    // 存储股票数据
    unordered_map<string, StockData> stock_map;
    
    // 检测挂单异常
    void detectOrderAbnormalities(const StockData& data, TestDetectionResult& result) {
        // 检查大托单(一般出目前出货试盘)
        if (data.bid_volumes[0] > 5 * data.bid_volumes[1] && 
            data.bid_volumes[0] > 1000000) { // 假设100万股为大单
            result.indicators.push_back("BIG_BID_ORDER");
            result.downward_prob += 0.15; // 出货试盘特征
        }
        
        // 检查大压单(一般出目前拉升试盘)
        if (data.ask_volumes[0] > 5 * data.ask_volumes[1] && 
            data.ask_volumes[0] > 1000000) {
            result.indicators.push_back("BIG_ASK_ORDER");
            result.upward_prob += 0.15; // 拉升试盘特征
        }
        
        // 检查夹板单(可能出目前两种试盘中)
        if (data.bid_volumes[2] > 500000 && data.ask_volumes[2] > 500000 &&
            (data.ask_prices[2] - data.bid_prices[2]) < (0.005 * data.last_price)) {
            result.indicators.push_back("SANDWICH_ORDER");
            // 夹板单本身不直接表明方向,但增加整体试盘概率
            result.upward_prob += 0.05;
            result.downward_prob += 0.05;
        }
    }
    
    // 检测价格异动
    void detectPriceAnomalies(const string& ticker, TestDetectionResult& result) {
        if (stock_map.find(ticker) == stock_map.end() || 
            stock_map[ticker].price_history.size() < VOLUME_ANALYSIS_WINDOW) {
            return;
        }
        
        const auto& data = stock_map[ticker];
        const auto& prices = data.price_history;
        
        // 计算价格波动范围
        double max_price = *max_element(prices.begin(), prices.end());
        double min_price = *min_element(prices.begin(), prices.end());
        double price_range = max_price - min_price;
        
        // 检测长上影线(出货试盘特征)
        if (max_price > data.last_price) {
            double upper_shadow = max_price - data.last_price;
            if (upper_shadow > SHADOW_RATIO_THRESHOLD * price_range) {
                result.indicators.push_back("UPPER_SHADOW");
                result.downward_prob += 0.25; // 出货试盘特征
            }
        }
        
        // 检测长下影线(拉升试盘特征)
        if (min_price < data.last_price) {
            double lower_shadow = data.last_price - min_price;
            if (lower_shadow > SHADOW_RATIO_THRESHOLD * price_range) {
                result.indicators.push_back("LOWER_SHADOW");
                result.upward_prob += 0.25; // 拉升试盘特征
            }
        }
        
        // 检测快速拉升(拉升试盘特征)
        // 检测快速打压(出货试盘特征)
        double max_up_change = 0.0;
        double max_down_change = 0.0;
        
        for (size_t i = 1; i < prices.size(); ++i) {
            double change = (prices[i] - prices[i-1]) / prices[i-1];
            
            if (change > max_up_change) {
                max_up_change = change;
            }
            if (change < max_down_change) {
                max_down_change = change;
            }
        }
        
        // 快速拉升特征
        if (max_up_change > PRICE_CHANGE_THRESHOLD) {
            result.indicators.push_back("RAPID_UP_PRICE_CHANGE");
            result.upward_prob += 0.3;
        }
        
        // 快速打压特征
        if (abs(max_down_change) > PRICE_CHANGE_THRESHOLD) {
            result.indicators.push_back("RAPID_DOWN_PRICE_CHANGE");
            result.downward_prob += 0.3;
        }
    }
    
    // 检测成交量异常
    void detectVolumeAnomalies(const string& ticker, TestDetectionResult& result) {
        if (stock_map.find(ticker) == stock_map.end() || 
            stock_map[ticker].volume_history.size() < VOLUME_ANALYSIS_WINDOW) {
            return;
        }
        
        const auto& data = stock_map[ticker];
        const auto& volumes = data.volume_history;
        int64_t current_volume = volumes.back();
        
        // 计算平均成交量
        int64_t sum_volume = 0;
        for (int i = 0; i < volumes.size() - 1; ++i) {
            sum_volume += volumes[i];
        }
        double avg_volume = static_cast<double>(sum_volume) / (volumes.size() - 1);
        
        // 检测成交量突增(可能出目前两种试盘中)
        if (avg_volume > 0 && current_volume > VOLUME_RATIO_THRESHOLD * avg_volume) {
            result.indicators.push_back("VOLUME_SPIKE");
            
            // 结合价格方向判断试盘类型
            if (!data.price_changes.empty()) {
                double last_price_change = data.price_changes.back();
                if (last_price_change > 0) {
                    result.upward_prob += 0.2; // 价量齐升 - 拉升试盘
                } else if (last_price_change < 0) {
                    result.downward_prob += 0.2; // 价跌量增 - 出货试盘
                } else {
                    // 量增价平 - 两种可能性都有
                    result.upward_prob += 0.1;
                    result.downward_prob += 0.1;
                }
            }
        }
        
        // 检测脉冲式成交量(快速试盘的典型特征)
        if (volumes.size() >= 3) {
            int64_t prev_volume = volumes[volumes.size()-2];
            int64_t prev_prev_volume = volumes[volumes.size()-3];
            
            if (current_volume > 4 * prev_volume && 
                prev_prev_volume > 0.8 * prev_volume) {
                result.indicators.push_back("VOLUME_PULSE");
                // 脉冲式成交量增加整体试盘概率
                result.upward_prob += 0.15;
                result.downward_prob += 0.15;
            }
        }
    }
    
    // 检测价格恢复情况
    void detectPriceRecovery(const string& ticker, TestDetectionResult& result) {
        if (stock_map.find(ticker) == stock_map.end() || 
            stock_map[ticker].price_history.size() < 5) {
            return;
        }
        
        const auto& data = stock_map[ticker];
        const auto& prices = data.price_history;
        size_t n = prices.size();
        
        // 检测拉升后的价格回落(出货试盘特征)
        if (prices[n-3] < prices[n-2] && prices[n-2] > prices[n-1]) {
            double recovery_ratio = (prices[n-2] - prices[n-1]) / (prices[n-2] - prices[n-3]);
            if (recovery_ratio > RECOVERY_THRESHOLD) {
                result.indicators.push_back("UP_PRICE_RECOVERY");
                result.downward_prob += 0.2; // 快速回落表明上方压力大,可能是出货试盘
            }
        }
        
        // 检测打压后的价格回升(拉升试盘特征)
        if (prices[n-3] > prices[n-2] && prices[n-2] < prices[n-1]) {
            double recovery_ratio = (prices[n-1] - prices[n-2]) / (prices[n-3] - prices[n-2]);
            if (recovery_ratio > RECOVERY_THRESHOLD) {
                result.indicators.push_back("DOWN_PRICE_RECOVERY");
                result.upward_prob += 0.2; // 快速回升表明下方支撑强,可能是拉升试盘
            }
        }
    }
    
public:
    // 更新市场数据
    void updateMarketData(const XTPMD* market_data) {
        string ticker(market_data->ticker);
        
        // 初始化或更新股票数据
        if (stock_map.find(ticker) == stock_map.end()) {
            stock_map[ticker] = StockData();
            stock_map[ticker].ticker = ticker;
        }
        
        auto& data = stock_map[ticker];
        double prev_price = data.last_price;
        data.last_price = market_data->last_price;
        data.pre_close = market_data->pre_close_price;
        data.volume = market_data->qty;
        data.turnover = market_data->turnover;
        data.timestamp = high_resolution_clock::now();
        
        // 计算价格变动
        if (prev_price > 0) {
            double price_change = (data.last_price - prev_price) / prev_price;
            data.price_changes.push_back(price_change);
            if (data.price_changes.size() > VOLUME_ANALYSIS_WINDOW) {
                data.price_changes.pop_front();
            }
        }
        
        // 更新买卖盘口
        for (int i = 0; i < 5; ++i) {
            data.bid_prices[i] = market_data->bid[i];
            data.ask_prices[i] = market_data->ask[i];
            data.bid_volumes[i] = market_data->bid_qty[i];
            data.ask_volumes[i] = market_data->ask_qty[i];
        }
        
        // 更新价格和成交量历史
        data.price_history.push_back(data.last_price);
        data.volume_history.push_back(data.volume);
        
        // 保持历史数据在窗口大小内
        if (data.price_history.size() > VOLUME_ANALYSIS_WINDOW) {
            data.price_history.pop_front();
        }
        if (data.volume_history.size() > VOLUME_ANALYSIS_WINDOW) {
            data.volume_history.pop_front();
        }
    }
    
    // 检测试盘行为
    TestDetectionResult detectTestPattern(const string& ticker) {
        TestDetectionResult result;
        
        if (stock_map.find(ticker) == stock_map.end()) {
            return result;
        }
        
        const auto& data = stock_map[ticker];
        
        // 1. 检测挂单异常
        detectOrderAbnormalities(data, result);
        
        // 2. 检测价格异动
        detectPriceAnomalies(ticker, result);
        
        // 3. 检测成交量异常
        detectVolumeAnomalies(ticker, result);
        
        // 4. 检测价格恢复情况
        detectPriceRecovery(ticker, result);
        
        // 5. 确定试盘类型
        double max_prob = max(result.upward_prob, result.downward_prob);
        
        if (max_prob < TEST_PROBABILITY_THRESHOLD) {
            result.test_type = NO_TEST;
        } else {
            if (result.upward_prob > result.downward_prob) {
                result.test_type = UPWARD_TEST;
            } else if (result.downward_prob > result.upward_prob) {
                result.test_type = DOWNWARD_TEST;
            } else {
                result.test_type = AMBIGUOUS_TEST;
            }
        }
        
        // 概率上限为1.0
        result.upward_prob = min(result.upward_prob, 1.0);
        result.downward_prob = min(result.downward_prob, 1.0);
        
        return result;
    }
    
    // 清理过期数据
    void cleanExpiredData() {
        auto now = high_resolution_clock::now();
        
        for (auto it = stock_map.begin(); it != stock_map.end(); ) {
            auto duration = duration_cast<seconds>(now - it->second.timestamp);
            if (duration.count() > TIME_WINDOW_SECONDS * 2) {
                it = stock_map.erase(it);
            } else {
                ++it;
            }
        }
    }
};

// XTP行情回调处理类
class QuoteSpi : public XTP::API::QuoteSpi {
private:
    MarketAnalyzer analyzer;
    
    // 将TestType转换为字符串
    string testTypeToString(TestType type) {
        switch(type) {
            case NO_TEST: return "无试盘";
            case UPWARD_TEST: return "拉升试盘";
            case DOWNWARD_TEST: return "出货试盘";
            case AMBIGUOUS_TEST: return "模棱两可";
            default: return "未知";
        }
    }
    
public:
    // 深度行情通知
    virtual void OnDepthMarketData(XTPMD *market_data, int64_t bid1_qty[], int32_t bid1_count, int32_t max_bid1_count, 
                                  int64_t ask1_qty[], int32_t ask1_count, int32_t max_ask1_count) {
        // 更新市场数据
        analyzer.updateMarketData(market_data);
        
        // 检测试盘模式
        string ticker(market_data->ticker);
        TestDetectionResult result = analyzer.detectTestPattern(ticker);
        
        // 输出检测结果
        if (result.test_type != NO_TEST) {
            cout << "
[试盘检测] " << ticker 
                 << " | 类型: " << testTypeToString(result.test_type)
                 << " | 拉升概率: " << result.upward_prob * 100 << "%"
                 << " | 出货概率: " << result.downward_prob * 100 << "%"
                 << " | 指标: ";
            
            for (const auto& ind : result.indicators) {
                cout << ind << " ";
            }
            cout << endl;
            
            // 根据试盘类型采取不同策略
            switch(result.test_type) {
                case UPWARD_TEST:
                    // 拉升试盘 - 思考逢低买入
                    cout << "  策略提议: 关注回踩机会,设置买入条件单" << endl;
                    break;
                case DOWNWARD_TEST:
                    // 出货试盘 - 思考逢高卖出
                    cout << "  策略提议: 警惕上方压力,设置止盈止损" << endl;
                    break;
                case AMBIGUOUS_TEST:
                    // 模棱两可 - 保持观望
                    cout << "  策略提议: 保持观望,等待更多信号" << endl;
                    break;
                default:
                    break;
            }
        }
    }
    
    // 其他回调方法
    virtual void OnSubscribeAllMarketData(XTP_EXCHANGE_TYPE exchange_id, XTPRI *error_info) {}
    virtual void OnUnSubscribeAllMarketData(XTP_EXCHANGE_TYPE exchange_id, XTPRI *error_info) {}
    virtual void OnQueryAllTickersFullInfo(XTPQFI* ticker_info, XTPRI *error_info, bool is_last) {}
};

// 主函数
int main() {
    // 创建行情API实例
    XTP::API::QuoteApi* quote_api = XTP::API::QuoteApi::CreateQuoteApi("client_id", "./log/");
    
    if (!quote_api) {
        cerr << "创建行情API实例失败" << endl;
        return 1;
    }
    
    // 创建回调处理实例
    QuoteSpi quote_spi;
    quote_api->RegisterSpi("e_spi);
    
    // 登录行情服务器
    XTPRI login_result;
    const char* ip = "120.27.164.138"; // XTP服务器IP
    int port = 6002;                   // 行情端口
    const char* username = "username"; // 替换为实际用户名
    const char* password = "password"; // 替换为实际密码
    
    int session_id = quote_api->Login(ip, port, username, password, XTP_PROTOCOL_TCP);
    
    if (session_id == 0 || login_result.error_id != 0) {
        cerr << "登录失败: " << login_result.error_msg << endl;
        quote_api->Release();
        return 1;
    }
    
    cout << "登录成功. 会话ID: " << session_id << endl;
    
    // 订阅行情
    vector<string> tickers = {"600000", "000001", "600519", "000858"}; // 示例股票代码
    vector<XTP_EXCHANGE_TYPE> exchanges = {
        XTP_EXCHANGE_SH, // 上证
        XTP_EXCHANGE_SZ, // 深证
        XTP_EXCHANGE_SH, // 上证
        XTP_EXCHANGE_SZ  // 深证
    };
    
    for (size_t i = 0; i < tickers.size(); ++i) {
        int ret = quote_api->SubscribeMarketData(tickers[i].c_str(), exchanges[i]);
        if (ret != 0) {
            cerr << "订阅 " << tickers[i] << " 失败" << endl;
        } else {
            cout << "已订阅 " << tickers[i] << endl;
        }
    }
    
    // 主循环
    cout << "
开始监控试盘行为..." << endl;
    cout << "----------------------------------------" << endl;
    
    while (true) {
        // 定期清理过期数据
        quote_spi.cleanExpiredData();
        
        // 休眠一段时间,避免CPU过度占用
        this_thread::sleep_for(milliseconds(100));
    }
    
    // 清理
    quote_api->Logout();
    quote_api->Release();
    
    return 0;
}
  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部