Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ if(OPTIONX_BUILD_TESTS)
market_data_tick_history_contract_test
market_data_tick_continuity_test
intrade_observed_tick_history_test
trading_system_batch1_test
)
if(OPTIONX_LIGHTWEIGHT_BRIDGE_SMOKE_TESTS)
list(APPEND OPTIONX_LIGHTWEIGHT_TESTS
Expand Down
1 change: 1 addition & 0 deletions include/optionx_cpp/optionx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "utils.hpp"
#include "lifecycle.hpp"
#include "data.hpp"
#include "trading_system.hpp"
#include "market_data.hpp"
#include "storages.hpp"
#include "components.hpp"
Expand Down
14 changes: 14 additions & 0 deletions include/optionx_cpp/trading_system.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once
#ifndef OPTIONX_HEADER_TRADING_SYSTEM_HPP_INCLUDED
#define OPTIONX_HEADER_TRADING_SYSTEM_HPP_INCLUDED

/// \file trading_system.hpp
/// \brief Public aggregate for pure trading-system identity contracts.

#include <optionx_cpp/data/trading.hpp>

#include "trading_system/Identity.hpp"
#include "trading_system/TradeSeries.hpp"
#include "trading_system/TradeIntent.hpp"

#endif // OPTIONX_HEADER_TRADING_SYSTEM_HPP_INCLUDED
133 changes: 133 additions & 0 deletions include/optionx_cpp/trading_system/Identity.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#pragma once
#ifndef OPTIONX_HEADER_TRADING_SYSTEM_IDENTITY_HPP_INCLUDED
#define OPTIONX_HEADER_TRADING_SYSTEM_IDENTITY_HPP_INCLUDED

/// \file Identity.hpp
/// \brief Defines stable identities and cardinality policies for trading-system contracts.

#include <cstdint>
#include <nlohmann/json.hpp>
#include <stdexcept>
#include <string>

namespace optionx::trading_system {

using IntentId = std::uint64_t;
using SeriesId = std::uint64_t;
using ExecutionGroupId = std::uint64_t;
using SettlementId = std::uint64_t;

enum class IntentStatus {
PROPOSED,
REJECTED,
ADMITTED,
SUBMITTING,
EXECUTION_UNKNOWN,
EXECUTED,
SETTLED,
CANCELLED
};

enum class ExecutionCardinality {
ZERO_OR_ONE,
EXACTLY_ONE,
MULTIPLE,
SPLIT_GROUP
};

inline const char* to_string(IntentStatus value) noexcept {
switch (value) {
case IntentStatus::PROPOSED: return "PROPOSED";
case IntentStatus::REJECTED: return "REJECTED";
case IntentStatus::ADMITTED: return "ADMITTED";
case IntentStatus::SUBMITTING: return "SUBMITTING";
case IntentStatus::EXECUTION_UNKNOWN: return "EXECUTION_UNKNOWN";
case IntentStatus::EXECUTED: return "EXECUTED";
case IntentStatus::SETTLED: return "SETTLED";
case IntentStatus::CANCELLED: return "CANCELLED";
}
return "UNKNOWN";
}

inline const char* to_string(ExecutionCardinality value) noexcept {
switch (value) {
case ExecutionCardinality::ZERO_OR_ONE: return "ZERO_OR_ONE";
case ExecutionCardinality::EXACTLY_ONE: return "EXACTLY_ONE";
case ExecutionCardinality::MULTIPLE: return "MULTIPLE";
case ExecutionCardinality::SPLIT_GROUP: return "SPLIT_GROUP";
}
return "UNKNOWN";
}

inline IntentStatus intent_status_from_string(const std::string& value) {
if (value == "PROPOSED") return IntentStatus::PROPOSED;
if (value == "REJECTED") return IntentStatus::REJECTED;
if (value == "ADMITTED") return IntentStatus::ADMITTED;
if (value == "SUBMITTING") return IntentStatus::SUBMITTING;
if (value == "EXECUTION_UNKNOWN") return IntentStatus::EXECUTION_UNKNOWN;
if (value == "EXECUTED") return IntentStatus::EXECUTED;
if (value == "SETTLED") return IntentStatus::SETTLED;
if (value == "CANCELLED") return IntentStatus::CANCELLED;
throw std::invalid_argument("Unknown trading-system intent status: " + value);
}

inline ExecutionCardinality execution_cardinality_from_string(const std::string& value) {
if (value == "ZERO_OR_ONE") return ExecutionCardinality::ZERO_OR_ONE;
if (value == "EXACTLY_ONE") return ExecutionCardinality::EXACTLY_ONE;
if (value == "MULTIPLE") return ExecutionCardinality::MULTIPLE;
if (value == "SPLIT_GROUP") return ExecutionCardinality::SPLIT_GROUP;
throw std::invalid_argument("Unknown trading-system execution cardinality: " + value);
}

inline void to_json(nlohmann::json& json, IntentStatus value) {
json = to_string(value);
}

inline void from_json(const nlohmann::json& json, IntentStatus& value) {
value = intent_status_from_string(json.get<std::string>());
}

inline void to_json(nlohmann::json& json, ExecutionCardinality value) {
json = to_string(value);
}

inline void from_json(const nlohmann::json& json, ExecutionCardinality& value) {
value = execution_cardinality_from_string(json.get<std::string>());
}

/// \brief Identifies a physical execution group without owning execution state.
struct ExecutionGroupIdentity {
ExecutionGroupId group_id = 0;
std::uint32_t expected_members = 0;

/// \brief Checks whether this identity is compatible with a cardinality policy.
bool valid_for(ExecutionCardinality cardinality) const noexcept {
switch (cardinality) {
case ExecutionCardinality::ZERO_OR_ONE:
return group_id == 0 && expected_members <= 1;
case ExecutionCardinality::EXACTLY_ONE:
return expected_members == 1;
case ExecutionCardinality::MULTIPLE:
return group_id != 0 && expected_members >= 2;
case ExecutionCardinality::SPLIT_GROUP:
return group_id != 0 && expected_members >= 2;
}
return false;
}
};

inline void to_json(nlohmann::json& json, const ExecutionGroupIdentity& value) {
json = nlohmann::json{
{"group_id", value.group_id},
{"expected_members", value.expected_members}
};
}

inline void from_json(const nlohmann::json& json, ExecutionGroupIdentity& value) {
value.group_id = json.value("group_id", ExecutionGroupId{0});
value.expected_members = json.value("expected_members", std::uint32_t{0});
}

} // namespace optionx::trading_system

#endif // OPTIONX_HEADER_TRADING_SYSTEM_IDENTITY_HPP_INCLUDED
92 changes: 92 additions & 0 deletions include/optionx_cpp/trading_system/TradeIntent.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#pragma once
#ifndef OPTIONX_HEADER_TRADING_SYSTEM_TRADE_INTENT_HPP_INCLUDED
#define OPTIONX_HEADER_TRADING_SYSTEM_TRADE_INTENT_HPP_INCLUDED

/// \file TradeIntent.hpp
/// \brief Defines the pure intent envelope used before broker submission.

#include "Identity.hpp"

#include <cstdint>
#include <nlohmann/json.hpp>
#include <string>

namespace optionx::trading_system {

/// \class TradeIntent
/// \brief Identifies one proposed logical trade without executing it.
///
/// The embedded TradeRequest remains the existing broker-compatible request
/// DTO. This envelope adds identity, cardinality, and revision data without
/// changing TradeRequest serialization or runtime callback ownership.
struct TradeIntent {
IntentId intent_id = 0;
SignalId origin_signal_id = 0;
SeriesId series_id = 0;
std::int32_t series_step = -1;
ExecutionGroupIdentity execution_group;
ExecutionCardinality cardinality = ExecutionCardinality::ZERO_OR_ONE;
IntentStatus status = IntentStatus::PROPOSED;
TradeRequest request;
std::uint64_t state_revision = 0;
std::string idempotency_key;

/// \brief Validates identity and cardinality invariants only.
bool valid() const noexcept {
const bool standalone = series_id == 0 && series_step == -1;
const bool series_bound = series_id != 0 && series_step >= 0;
return intent_id != 0 &&
(standalone || series_bound) &&
!idempotency_key.empty() &&
execution_group.valid_for(cardinality);
}

bool revision_matches(std::uint64_t expected_revision) const noexcept {
return state_revision == expected_revision;
}

bool advance_revision(std::uint64_t expected_revision) noexcept {
if (!revision_matches(expected_revision)) return false;
++state_revision;
return true;
}

TradeIntent clone() const {
return *this;
}
};

inline void to_json(nlohmann::json& json, const TradeIntent& value) {
json = nlohmann::json{
{"intent_id", value.intent_id},
{"origin_signal_id", value.origin_signal_id},
{"series_id", value.series_id},
{"series_step", value.series_step},
{"execution_group", value.execution_group},
{"cardinality", value.cardinality},
{"status", value.status},
{"request", value.request},
{"state_revision", value.state_revision},
{"idempotency_key", value.idempotency_key}
};
}

inline void from_json(const nlohmann::json& json, TradeIntent& value) {
value.intent_id = json.value("intent_id", IntentId{0});
value.origin_signal_id = json.value("origin_signal_id", SignalId{0});
value.series_id = json.value("series_id", SeriesId{0});
value.series_step = json.value("series_step", std::int32_t{-1});
value.execution_group = json.value("execution_group", ExecutionGroupIdentity{});
value.cardinality = json.value("cardinality", ExecutionCardinality::ZERO_OR_ONE);
value.status = json.value("status", IntentStatus::PROPOSED);
value.request = TradeRequest{};
if (json.contains("request")) {
json.at("request").get_to(value.request);
}
value.state_revision = json.value("state_revision", std::uint64_t{0});
value.idempotency_key = json.value("idempotency_key", std::string{});
}

} // namespace optionx::trading_system

#endif // OPTIONX_HEADER_TRADING_SYSTEM_TRADE_INTENT_HPP_INCLUDED
63 changes: 63 additions & 0 deletions include/optionx_cpp/trading_system/TradeSeries.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#pragma once
#ifndef OPTIONX_HEADER_TRADING_SYSTEM_TRADE_SERIES_HPP_INCLUDED
#define OPTIONX_HEADER_TRADING_SYSTEM_TRADE_SERIES_HPP_INCLUDED

/// \file TradeSeries.hpp
/// \brief Defines the identity and revision envelope for a trade series.

#include "Identity.hpp"

#include <cstdint>
#include <nlohmann/json.hpp>

namespace optionx::trading_system {

/// \class TradeSeries
/// \brief Pure identity state for a future series progression component.
///
/// This type deliberately does not implement progression, settlement, risk,
/// or broker calls. Those concerns belong to later trading-system batches.
struct TradeSeries {
SeriesId series_id = 0;
SignalId origin_signal_id = 0;
std::uint32_t next_step = 0;
std::uint64_t state_revision = 0;

bool valid() const noexcept {
return series_id != 0;
}

bool revision_matches(std::uint64_t expected_revision) const noexcept {
return state_revision == expected_revision;
}

bool advance_revision(std::uint64_t expected_revision) noexcept {
if (!revision_matches(expected_revision)) return false;
++state_revision;
return true;
}

TradeSeries clone() const {
return *this;
}
};

inline void to_json(nlohmann::json& json, const TradeSeries& value) {
json = nlohmann::json{
{"series_id", value.series_id},
{"origin_signal_id", value.origin_signal_id},
{"next_step", value.next_step},
{"state_revision", value.state_revision}
};
}

inline void from_json(const nlohmann::json& json, TradeSeries& value) {
value.series_id = json.value("series_id", SeriesId{0});
value.origin_signal_id = json.value("origin_signal_id", SignalId{0});
value.next_step = json.value("next_step", std::uint32_t{0});
value.state_revision = json.value("state_revision", std::uint64_t{0});
}

} // namespace optionx::trading_system

#endif // OPTIONX_HEADER_TRADING_SYSTEM_TRADE_SERIES_HPP_INCLUDED
Loading
Loading