跳转至

k线生成器

#ifndef BAR_GENERATOR_H
#define BAR_GENERATOR_H

#include <algorithm>
#include <chrono>
#include <cstdint>
#include <functional>
#include <vector>

/**
 * @brief K线数据结构
 */
struct BarData {
  int64_t timestamp;  ///< K线时间戳(毫秒)
  double open;
  double high;
  double low;
  double close;
  double volume;
  double turnover;
};

/**
 * @brief K线周期类型
 */
enum class BarType {
  MINUTE_1 = 1,    ///< 1分钟K线
  MINUTE_5 = 5,    ///< 5分钟K线
  MINUTE_15 = 15,  ///< 15分钟K线
  MINUTE_30 = 30,  ///< 30分钟K线
  HOUR_1 = 60,     ///< 1小时K线
  DAY = 1440       ///< 日K线
};

/**
 * @brief 高性能K线生成器
 *
 * 该类用于接收市场tick数据并生成相应周期的K线数据。
 */
class BarGenerator {
 public:
  /**
   * @brief 构造函数
   * @param type K线周期类型
   * @param callback K线生成回调函数
   */
  BarGenerator(BarType type,
               std::function<void(const BarData&)> callback) noexcept
      : type_(type), callback_(std::move(callback)) {}

  /**
   * @brief 更新最新的tick数据
   * @param timestamp 时间戳(毫秒)
   * @param price 最新成交价格
   * @param volume 成交量
   * @param turnover 成交额
   */
  void update(int64_t timestamp, double price, double volume,
              double turnover) noexcept {
    // 计算当前tick应该属于哪个K线周期
    int64_t bar_start_time = calculateBarStartTime(timestamp);

    // 如果是新的K线周期
    if (!has_current_bar_ || bar_start_time > current_bar_start_time_) {
      // 如果存在之前的K线,则完成它
      if (has_current_bar_) {
        finishCurrentBar();
      }

      // 创建新的K线
      createNewBar(bar_start_time);
    }

    // 更新当前K线数据
    updateCurrentBar(price, volume, turnover);
  }

  /**
   * @brief 强制完成当前K线
   */
  void finishCurrentBar() noexcept {
    if (has_current_bar_) {
      // 调用回调函数,通知K线已完成
      callback_(current_bar_);
      has_current_bar_ = false;
    }
  }

  /**
   * @brief 获取当前正在构建的K线
   * @return 当前K线数据的指针,如果不存在则返回nullptr
   */
  const BarData* getCurrentBar() const noexcept {
    if (has_current_bar_) {
      return &current_bar_;
    }
    return nullptr;
  }

  /**
   * @brief 获取K线周期类型
   * @return K线周期类型
   */
  BarType getType() const noexcept { return type_; }

 private:
  /**
   * @brief 根据时间戳计算K线开始时间
   * @param timestamp 时间戳(毫秒)
   * @return K线开始时间戳(毫秒)
   */
  int64_t calculateBarStartTime(int64_t timestamp) const noexcept {
    // 将毫秒时间戳转换为分钟数
    int64_t minutes = timestamp / 60000;

    // 根据K线类型计算开始时间
    int64_t bar_minutes = 0;
    switch (type_) {
      case BarType::MINUTE_1:
        bar_minutes = minutes;
        break;
      case BarType::MINUTE_5:
        bar_minutes = (minutes / 5) * 5;
        break;
      case BarType::MINUTE_15:
        bar_minutes = (minutes / 15) * 15;
        break;
      case BarType::MINUTE_30:
        bar_minutes = (minutes / 30) * 30;
        break;
      case BarType::HOUR_1:
        bar_minutes = (minutes / 60) * 60;
        break;
      case BarType::DAY:
        bar_minutes = (minutes / 1440) * 1440;
        break;
    }

    // 转换回毫秒时间戳
    return bar_minutes * 60000;
  }

  /**
   * @brief 创建新的K线
   * @param timestamp 时间戳(毫秒)
   */
  void createNewBar(int64_t timestamp) noexcept {
    current_bar_start_time_ = timestamp;
    current_bar_.timestamp = timestamp;
    // 其他字段将在updateCurrentBar中更新
    has_current_bar_ = true;
  }

  /**
   * @brief 更新当前K线数据
   * @param price 最新成交价格
   * @param volume 成交量
   * @param turnover 成交额
   */
  void updateCurrentBar(double price, double volume, double turnover) noexcept {
    if (volume == 0 && turnover == 0) {
      return;  // 没有实际成交,不更新
    }

    if (current_bar_.volume == 0) {
      // 第一笔成交,初始化OHLC
      current_bar_.open = price;
      current_bar_.high = price;
      current_bar_.low = price;
      current_bar_.close = price;
    } else {
      // 更新最高价和最低价
      current_bar_.high = std::max(current_bar_.high, price);
      current_bar_.low = std::min(current_bar_.low, price);
      current_bar_.close = price;
    }

    // 累加成交量和成交额
    current_bar_.volume += volume;
    current_bar_.turnover += turnover;
  }

 private:
  BarType type_;                                  ///< K线周期类型
  std::function<void(const BarData&)> callback_;  ///< K线生成回调函数
  BarData current_bar_{};                         ///< 当前正在构建的K线
  int64_t current_bar_start_time_ = 0;            ///< 当前K线开始时间
  bool has_current_bar_ = false;                  ///< 是否存在正在构建的K线
};

#endif  // BAR_GENERATOR_H