The Replay sample feeds previously recorded market data back into the handler without requiring live multicast connectivity. It supports handler logs, PCAP captures, and CME DataMine historical files, and can fall back to matching sample data from ../Data, making it useful for debugging, regression checks, and offline development.
class Configuration
: public ChannelConfiguration
, public ConnectivityConfiguration
, public LoggerConfiguration
{
public:
Configuration(size_t qty, char** args)
: ConfigurationBase(qty, args)
, ChannelConfiguration(qty, args, 310)
, ConnectivityConfiguration(qty, args)
, LoggerConfiguration(qty, args, "Replay.log")
{
const unsigned optionQty = countOption("log") + countOption("pcap") + countOption("datamine");
if (1 < optionQty)
{
throw std::runtime_error("Cannot initialize market data replay "
"due to conflict in the input parameters. "
"Multiple replay sources (Log, PCAP, DataMine) "
"selected at the same time. Please, fix the command "
"line arguments to use only one type of market data "
"source (either log or PCAP or DataMine). ");
}
}
bool replayPcap() const
{
return exist(options(), "pcap");
}
bool replayDatamine() const
{
return exist(options(), "datamine");
}
bool filesToReplay(FileList& files) const
{
const OptionArgs* args = options().args("log");
if (!args)
{
args = options().args("pcap");
if (!args)
{
args = options().args("datamine");
}
}
if (args)
{
std::copy(args->begin(), args->end(), std::back_inserter(files));
return true;
}
return false;
}
private:
unsigned countOption(const char* name) const
{
assert(nullptr != name);
return exist(options(), name) ? 1 : 0;
}
void showOptions(std::ostream& out) const override
{
out << " --log [file1 [file2 [..]]]" << std::endl
<< "\tTells to replay the given list of log files. " << std::endl
<< "\tIf no files are specified, sample data is replayed. " << std::endl
<< std::endl
<< " --pcap [file1 [file2 [..]]]" << std::endl
<< "\tTells to replay the given list of PCAP files. " << std::endl
<< "\tIf no files are specified, sample data is replayed. " << std::endl
<< std::endl
<< " --datamine [file1 [file2 [..]]]" << std::endl
<< "\tTells to replay the given list of CME DataMine (historical) files. " << std::endl
<< "\tIf no files are specified, sample data is replayed. " << std::endl
<< std::endl;
ChannelConfiguration::showOptions(out);
ConnectivityConfiguration::showOptions(out);
LoggerConfiguration::showOptions(out);
}
};
class ReplayManager
{
public:
virtual ~ReplayManager() {}
virtual void gather(FileList&, const std::string&, ChannelId) = 0;
virtual void configure(HandlerSettings&) = 0;
virtual void replay(const FileList&, Handler&) = 0;
protected:
ReplayManager() {}
};
struct LogReplayManager : ReplayManager
{
LogReplayManager() {}
void gather(FileList& list, const std::string& folder, ChannelId channel) override
{
}
void configure(HandlerSettings& ) override
{
}
void replay(const FileList& files, Handler& handler) override
{
}
};
class PcapReplayManager : public ReplayManager
{
public:
PcapReplayManager() {}
{
return supplements_.aliases();
}
void gather(FileList& files, const std::string& folder, ChannelId) override
{
}
void configure(HandlerSettings& settings) override
{
}
void replay(const FileList& files, Handler& handler) override
{
if (supplements_.aliases().empty())
{
}
else
{
}
}
private:
PcapReplaySettings supplements_;
};
class DatamineReplayManager : public ReplayManager
{
public:
explicit DatamineReplayManager(bool useInstrumentCache)
: instruments_(useInstrumentCache ? "../Data/SecDef-310.dat" : "")
{
}
void gather(FileList& files, const std::string& folder, ChannelId) override
{
}
void configure(HandlerSettings& settings) override
{
instruments_.empty() ? JoinRecoveryOptions::Disabled : JoinRecoveryOptions::Instruments
);
}
void replay(const FileList& files, Handler& handler) override
{
}
private:
std::string instruments_;
};
class Application
{
public:
Application(const Configuration& configuration)
: configuration_(configuration)
{
configuration_.filesToReplay(files_);
if (configuration_.replayPcap())
{
ScopedPtr<PcapReplayManager> pcapManager(new PcapReplayManager());
if (files_.empty())
{
pcapManager->aliases()[NetFeedConnection("224.0.31.1", 14310)] = NetFeedConnection("224.0.28.1", 14310);
}
replayManager_.reset(pcapManager.release());
}
else if (configuration_.replayDatamine())
{
replayManager_.reset(new DatamineReplayManager(files_.empty()));
}
else
{
replayManager_.reset(new LogReplayManager());
}
if (files_.empty())
{
replayManager_->gather(files_, "../Data", configuration_.channel());
}
}
~Application() {}
void run()
{
FileLoggerEventTracer loggerTracer;
const ScopedPtr<Logger> logger(constructFileLogger(configuration_, &loggerTracer));
setLicense(settings);
settings.
channel(configuration_.channel()).connectivityConfigurationFile(configuration_.connectivityFile());;
replayManager_->configure(settings);
apply(settings.
logging(), configuration_, logger.get());
SecurityEventTracer securityEventTracer;
securityEventTracer.bind(handler);
MarketDataEventTracer marketDataTracer;
marketDataTracer.bind(handler);
ServiceEventTracer serviceTracer;
serviceTracer.bind(handler);
std::cout << "Replaying the recorded market data.. " << std::endl;
replayManager_->replay(files_, handler);
std::cout << std::endl << "Done. " << std::endl << std::endl;
}
static void identify()
{
std::cout <<
"Market Data Replay for the CME MDP Premium Market Data Handler, v" <<
toStr(
Version::current())
<< ". "
<< std::endl
<< std::endl;
}
private:
const Configuration& configuration_;
ScopedPtr<ReplayManager> replayManager_;
Application(const Application&);
Application& operator=(const Application&);
};
int main(int qty, char** args)
{
try
{
Application::identify();
const Configuration configuration(qty, args);
if (configuration.show())
{
configuration.show(std::cout);
}
else
{
Application(configuration).run();
}
return 0;
}
catch (const std::exception& ex)
{
std::cerr << std::endl << "ERROR: " << ex.what() << std::endl;
return 1;
}
}