86 lines
2.9 KiB
C++
86 lines
2.9 KiB
C++
#pragma once
|
|
#include <string>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
#include <queue>
|
|
#include <numeric>
|
|
|
|
#include "events.hpp"
|
|
#include "data_handler.hpp"
|
|
|
|
// ── Strategy base ─────────────────────────────────────────────────────────────
|
|
|
|
class Strategy {
|
|
public:
|
|
virtual void calculate_signals(const Event& event) = 0;
|
|
virtual ~Strategy() = default;
|
|
};
|
|
|
|
// ── SMA Crossover ─────────────────────────────────────────────────────────────
|
|
//
|
|
// Long when fast_ma > slow_ma
|
|
// Exit when fast_ma < slow_ma
|
|
|
|
class SMACrossStrategy : public Strategy {
|
|
public:
|
|
struct TradeRecord {
|
|
std::string date;
|
|
std::string symbol;
|
|
std::string signal; // "BUY" | "SELL"
|
|
};
|
|
|
|
SMACrossStrategy(const std::vector<std::string>& symbols,
|
|
std::queue<Event>& events,
|
|
DataHandler& data,
|
|
int fast = 20,
|
|
int slow = 50)
|
|
: symbols_(symbols), events_(events), data_(data),
|
|
fast_(fast), slow_(slow)
|
|
{
|
|
for (const auto& s : symbols_)
|
|
invested_[s] = false;
|
|
}
|
|
|
|
void calculate_signals(const Event& event) override {
|
|
if (!std::holds_alternative<MarketEvent>(event)) return;
|
|
|
|
for (const auto& sym : symbols_) {
|
|
auto bars = data_.get_latest_bars(sym, slow_ + 1);
|
|
if (static_cast<int>(bars.size()) < slow_) continue;
|
|
|
|
double fast_ma = mean_close(bars, fast_);
|
|
double slow_ma = mean_close(bars, slow_);
|
|
|
|
if (fast_ma > slow_ma && !invested_[sym]) {
|
|
events_.push(SignalEvent{ sym, Direction::LONG });
|
|
invested_[sym] = true;
|
|
trade_log_.push_back({ data_.current_date(), sym, "BUY" });
|
|
|
|
} else if (fast_ma < slow_ma && invested_[sym]) {
|
|
events_.push(SignalEvent{ sym, Direction::EXIT });
|
|
invested_[sym] = false;
|
|
trade_log_.push_back({ data_.current_date(), sym, "SELL" });
|
|
}
|
|
}
|
|
}
|
|
|
|
const std::vector<TradeRecord>& trade_log() const { return trade_log_; }
|
|
|
|
private:
|
|
std::vector<std::string> symbols_;
|
|
std::queue<Event>& events_;
|
|
DataHandler& data_;
|
|
int fast_, slow_;
|
|
std::unordered_map<std::string, bool> invested_;
|
|
std::vector<TradeRecord> trade_log_;
|
|
|
|
// Mean of the last n closing prices in bars
|
|
static double mean_close(const std::vector<Bar>& bars, int n) {
|
|
int start = static_cast<int>(bars.size()) - n;
|
|
double sum = 0.0;
|
|
for (int i = start; i < static_cast<int>(bars.size()); ++i)
|
|
sum += bars[i].close;
|
|
return sum / n;
|
|
}
|
|
};
|