Skip to content

Commit

Permalink
[EN-7412] Implement DXFeedConnect sample
Browse files Browse the repository at this point in the history
  • Loading branch information
AnatolyKalin committed Sep 5, 2023
1 parent 21e5efc commit 49c77cb
Show file tree
Hide file tree
Showing 6 changed files with 244 additions and 24 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ set(dxFeedGraalCxxApi_Internal_Sources
set(dxFeedGraalCxxApi_InternalUtils_Sources
src/internal/utils/StringUtils.cpp
src/internal/utils/EnumUtils.cpp
src/internal/utils/TimeFormat.cpp
src/internal/utils/CmdArgsUtils.cpp
)

Expand Down
1 change: 1 addition & 0 deletions include/dxfeed_graal_cpp_api/api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "internal/utils/StringUtils.hpp"
#include "internal/utils/CmdArgsUtils.hpp"
#include "internal/utils/EnumUtils.hpp"
#include "internal/utils/TimeFormat.hpp"
#include "internal/utils/debug/Debug.hpp"

#include "api/ApiModule.hpp"
Expand Down
142 changes: 142 additions & 0 deletions include/dxfeed_graal_cpp_api/internal/utils/TimeFormat.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright (c) 2023 Devexperts LLC.
// SPDX-License-Identifier: MPL-2.0

#pragma once

#include "../Conf.hpp"

#include <cstddef>
#include <cstdint>
#include <locale>
#include <optional>
#include <set>
#include <string>
#include <thread>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>

namespace dxfcpp {

/**
* Utility class for parsing and formatting dates and times in ISO-compatible format.
*/
struct DXFCPP_EXPORT TimeFormat {
template <typename Entry, std::size_t maxSize = 256>
requires requires(Entry e) {
{ Entry{typename Entry::KeyType{}, typename Entry::ValueType{}} };
{ Entry::STUB } -> std::convertible_to<Entry>;
{ e.getKey() } -> std::convertible_to<typename Entry::KeyType>;
{ e.getValue() } -> std::convertible_to<typename Entry::ValueType>;
}
class Cache {
std::vector<Entry> data_{maxSize, Entry::STUB};

public:
void add(const Entry &entry) noexcept {
auto index = static_cast<std::size_t>(entry.getKey()) % maxSize;

data_[index] = entry;
}

void add(const Entry::KeyType &key, const Entry::ValueType &value) {
add({key, value});
}

template <typename Key> const Entry &get(const Key &key) const noexcept {
auto index = static_cast<std::size_t>(key) % maxSize;

if (data_[index].getKey() == key) {
return data_[index];
}

return Entry::STUB;
}

template <typename Key>
std::optional<std::reference_wrapper<const typename Entry::ValueType>>
getEntryValue(const Key &key) const noexcept {
auto index = static_cast<std::size_t>(key) % maxSize;

if (data_[index].getKey() == key) {
return data_[index].getValue();
}

return std::nullopt;
}
};

private:
struct DXFCPP_EXPORT MinuteCacheEntry {
using KeyType = std::int64_t;
using ValueType = std::string;

static const MinuteCacheEntry STUB;

private:
KeyType minute_{};
ValueType template_{};

public:
MinuteCacheEntry(KeyType minute, const ValueType &templat) noexcept : minute_{minute}, template_{templat} {
}

MinuteCacheEntry() noexcept : MinuteCacheEntry(std::numeric_limits<KeyType>::min(), "") {
}

KeyType getKey() const noexcept {
return minute_;
}

const ValueType &getValue() const noexcept {
return template_;
}

KeyType getMinute() const {
return minute_;
}

const ValueType &getTemplate() const {
return template_;
}

bool operator==(const MinuteCacheEntry &minuteCacheEntry) const noexcept {
return minute_ == minuteCacheEntry.minute_ && template_ == minuteCacheEntry.template_;
}
};

struct DXFCPP_EXPORT CacheEntry {
using KeyType = std::int64_t;
using ValueType = std::string;

static const CacheEntry STUB;

private:
KeyType key_{};
ValueType value_{};

public:
CacheEntry(KeyType key, const ValueType &value) noexcept : key_{key}, value_{value} {
}

CacheEntry() noexcept : CacheEntry(std::numeric_limits<KeyType>::min(), "") {
}

KeyType getKey() const noexcept {
return key_;
}

const ValueType &getValue() const noexcept {
return value_;
}

bool operator==(const CacheEntry &cacheEntry) const noexcept {
return key_ == cacheEntry.key_ && value_ == cacheEntry.value_;
}
};

class Format {};
};

} // namespace dxfcpp
104 changes: 83 additions & 21 deletions samples/cpp/DxFeedConnect/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,83 @@ using namespace std::literals;
void printUsage() {
auto usageString = R"(
Usage:
DxFeedFileParser <file> <type> <symbol>
DxFeedConnect <address> <types> <symbols> [<time>]
Where:
file - Is a file name.
type - Is comma-separated list of dxfeed event types ()" +
address - The address to connect to retrieve data (remote host or local tape file).
To pass an authorization token, add to the address: "[login=entitle:<token>]",
e.g.: demo.dxfeed.com:7300[login=entitle:<token>]
types - Is comma-separated list of dxfeed event types ()" +
dxfcpp::enum_utils::getEventTypeEnumNamesList() + R"().
symbol - Is comma-separated list of symbol names to get events for (e.g. "IBM,AAPL,MSFT").)";
symbols - Is comma-separated list of symbol names to get events for (e.g. "IBM,AAPL,MSFT").
for Candle event specify symbol with aggregation like in "AAPL{=d}"
time - Is from-time for history subscription in standard formats.
Same examples of valid from-time:
20070101-123456
20070101-123456.123
2005-12-31 21:00:00
2005-12-31 21:00:00.123+03:00
2005-12-31 21:00:00.123+0400
2007-11-02Z
123456789 - value-in-milliseconds
Examples:
DXFeedConnect demo.dxfeed.com:7300 Quote,Trade MSFT,IBM
DXFeedConnect demo.dxfeed.com:7300 TimeAndSale AAPL
DXFeedConnect demo.dxfeed.com:7300 Candle AAPL{=d} 20230201Z)";

std::cout << usageString << std::endl;
}

struct E {
using KeyType = std::int64_t;
using ValueType = std::string;

static const E STUB;

KeyType key{};
ValueType value{};

const KeyType &getKey() const noexcept {
return key;
}

const ValueType &getValue() const noexcept {
return value;
}
};

const E E::STUB{};

int main(int argc, char *argv[]) {
TimeFormat::Cache<E> cache{};

cache.add({1, "1"});

std::cout << "1:\n";

if (auto valueRefOpt = cache.getEntryValue(1); valueRefOpt) {
std::cout << valueRefOpt->get() << std::endl;
}

std::cout << "257:\n";

cache.add({257, "257"});

if (auto valueRefOpt = cache.getEntryValue(1); valueRefOpt) {
std::cout << valueRefOpt->get() << std::endl;
} else {
std::cout << " -- 1 " << std::endl;
}

if (auto valueRefOpt = cache.getEntryValue(257); valueRefOpt) {
std::cout << valueRefOpt->get() << std::endl;
} else {
std::cout << " -- 257 " << std::endl;
}

return 0;

if (argc < 4) {
printUsage();

Expand All @@ -35,36 +100,33 @@ int main(int argc, char *argv[]) {
std::mutex ioMtx{};

// Parse args.
std::string fileName = argv[1];
std::string address = argv[1];
auto types = CmdArgsUtils::parseTypes(argv[2]);
auto symbols = CmdArgsUtils::parseSymbols(argv[3]);

// Create endpoint specifically for file parsing.
auto endpoint = DXEndpoint::create(DXEndpoint::Role::STREAM_FEED);
auto feed = endpoint->getFeed();
if (argc >= 5) {
// std::chrono::parse
}

// Create an endpoint and connect to specified address.
auto endpoint = DXEndpoint::create()->connect(address);

// Subscribe to a specified event and symbol.
auto sub = feed->createSubscription(types);
sub->addEventListener([&eventCounter, &ioMtx](const auto &events) {
// Create a subscription with specified types attached to feed.
auto sub = endpoint->getFeed()->createSubscription(types);

// Add an event listener.
sub->addEventListener([&ioMtx](const auto &events) {
std::lock_guard lock{ioMtx};

for (auto &&e : events) {
std::cout << (++eventCounter) << ": " << e << "\n";
std::cout << e << "\n";
}
});

// Add symbols.
sub->addSymbols(symbols);

// Connect endpoint to a file.
endpoint->connect("file:" + fileName + "[speed=max]");

// Wait until file is completely parsed.
endpoint->awaitNotConnected();

// Close endpoint when we're done.
// This method will gracefully close endpoint, waiting while data processing completes.
endpoint->closeAndAwaitTermination();
std::cin.get();

return 0;
}
6 changes: 3 additions & 3 deletions samples/cpp/DxFeedFileParser/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ void printUsage() {
DxFeedFileParser <file> <type> <symbol>
Where:
file - Is a file name.
type - Is comma-separated list of dxfeed event types ()" +
file - Is a file name.
types - Is comma-separated list of dxfeed event types ()" +
dxfcpp::enum_utils::getEventTypeEnumNamesList() + R"().
symbol - Is comma-separated list of symbol names to get events for (e.g. "IBM,AAPL,MSFT").)";
symbols - Is comma-separated list of symbol names to get events for (e.g. "IBM,AAPL,MSFT").)";

std::cout << usageString << std::endl;
}
Expand Down
14 changes: 14 additions & 0 deletions src/internal/utils/TimeFormat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) 2023 Devexperts LLC.
// SPDX-License-Identifier: MPL-2.0

#include <dxfg_api.h>

#include <dxfeed_graal_c_api/api.h>
#include <dxfeed_graal_cpp_api/api.hpp>

namespace dxfcpp {

const TimeFormat::MinuteCacheEntry TimeFormat::MinuteCacheEntry::STUB{};
const TimeFormat::CacheEntry TimeFormat::CacheEntry::STUB{};

} // namespace dxfcpp

0 comments on commit 49c77cb

Please sign in to comment.