Common Code Patterns#
This page provides reusable code snippets for common OUCH 5.0 operations.
Session Setup#
Basic Session Initialization#
#include <nasdaq/ouch50/Session.h>
#include <nasdaq/ouch50/net/IOContext.h>
using namespace b2bits::nasdaq::ouch5;
// Create IO context
auto io_ctx = std::make_shared<IOContext>(IOContext::Settings{"main", 0, false});
io_ctx->start();
// Configure session
Settings settings;
settings.transport_.username_ = "TRADER01";
settings.transport_.password_ = "password123";
settings.transport_.remote_a_ = Endpoint{"192.168.1.100", 64002};
settings.initial_user_ref_num_ = 1;
// Create session
Session session(io_ctx, settings);
Session with Message Buffering#
Settings settings;
// ... basic settings ...
// Enable message buffering
OutboundMessageBufferSettings buffer_settings;
buffer_settings.max_messages_ = 10000;
buffer_settings.max_bytes_ = 10 * 1024 * 1024;
buffer_settings.track_acknowledgments_ = true;
settings.buffer_settings_ = buffer_settings;
settings.auto_retransmit_on_reconnect_ = true;
Session session(io_ctx, settings);
Listener Patterns#
Function Object Pattern#
struct Handler {
void operator()(Session* s, std::uint64_t seq, const OrderAccepted* msg) {
// Handle OrderAccepted
}
void operator()(Session* s, std::uint64_t seq, const OrderExecuted* msg) {
// Handle OrderExecuted
}
};
Handler handler;
session.attach_listener(std::ref(handler));
Lambda Pattern#
session.attach_listener(
[](Session* s, std::uint64_t seq, const OrderAccepted* msg) {
// Handle OrderAccepted
},
[](Session* s, std::uint64_t seq, const OrderExecuted* msg) {
// Handle OrderExecuted
}
);
Overloaded Pattern#
#include <nasdaq/common/Overloaded.h>
session.attach_listener(Overloaded(
[](Session* s, std::uint64_t seq, const OrderAccepted* msg) {
// Handle OrderAccepted
},
[](Session* s, std::uint64_t seq, const OrderExecuted* msg) {
// Handle OrderExecuted
}
));
Sending Orders#
Enter Order#
auto& refnum_gen = session.get_user_refnum_generator();
UInt32 user_ref_num = refnum_gen.next();
EnterOrder order;
order.set_user_ref_num(user_ref_num);
order.set_side(Side::Buy);
order.set_quantity(1000);
order.set_symbol("AAPL");
order.set_price(Price::from_double(150.50));
order.set_time_in_force(TimeInForce::Day);
order.set_display(DisplayFlag::Visible);
order.set_capacity(Capacity::Agency);
order.set_intermarket_sweep_elig('N');
order.set_cross_type(CrossType::None);
order.set_cl_ord_id("ORD001");
session.send_message(&order);
Replace Order#
ReplaceOrderRequest replace;
replace.set_orig_user_ref_num(orig_user_ref_num);
replace.set_user_ref_num(new_user_ref_num); // Must be strictly increasing
replace.set_quantity(2000);
replace.set_price(Price::from_double(150.75));
replace.set_time_in_force(TimeInForce::Day);
replace.set_display(DisplayFlag::Visible);
replace.set_intermarket_sweep_elig('N');
replace.set_cl_ord_id("ORD002");
session.send_message(&replace);
Cancel Order#
CancelOrderRequest cancel;
cancel.set_user_ref_num(user_ref_num);
cancel.set_quantity(0); // 0 = cancel all, >0 = partial cancel
session.send_message(&cancel);
TagValue Appendages#
Adding Optional Fields#
EnterOrder order;
// ... set required fields ...
// Add optional fields
auto& appendage = order.get_appendage_writer();
appendage.add_min_qty(100);
appendage.add_max_floor(5000);
appendage.add_firm("FIRM");
appendage.add_customer_type(CustomerType::Retail);
appendage.add_price_type(PriceType::Limit);
appendage.add_post_only(PostOnly::No);
appendage.add_expire_time(3600); // 1 hour
session.send_message(&order);
Reading Optional Fields#
void on_order_accepted(Session* s, std::uint64_t seq, const OrderAccepted* msg) {
// Using convenience accessor
if (auto min_qty = msg->get_min_qty()) {
std::cout << "MinQty: " << *min_qty << std::endl;
}
// Using appendage reader directly
auto appendage = msg->get_appendage();
if (auto element = appendage.find(TagValue::MIN_QTY)) {
UInt32 min_qty = element->as_uint32();
std::cout << "MinQty: " << min_qty << std::endl;
}
}
UserRefNum Management#
Generate UserRefNum#
auto& refnum_gen = session.get_user_refnum_generator();
UInt32 user_ref_num = refnum_gen.next(); // Strictly increasing
Recover UserRefNum#
// Send Account Query Request
AccountQueryRequest query;
session.send_message(&query);
// In AccountQueryResponse handler:
void on_account_query_response(Session* s, std::uint64_t seq, const AccountQueryResponse* msg) {
UInt32 next_user_ref_num = msg->get_next_user_ref_num();
s->get_user_refnum_generator().reset(next_user_ref_num);
}
Message Buffering#
Mark Messages as Acknowledged#
void on_order_accepted(Session* s, std::uint64_t seq, const OrderAccepted* msg) {
if (auto* buffer = s->get_message_buffer()) {
buffer->mark_acknowledged(msg->get_user_ref_num());
}
}
void on_order_replaced(Session* s, std::uint64_t seq, const OrderReplaced* msg) {
if (auto* buffer = s->get_message_buffer()) {
buffer->mark_acknowledged(msg->get_user_ref_num());
}
}
Thread Safety#
Sending from Another Thread#
// From main thread or other thread
io_ctx->post([session = session.get(), order]() {
// Now on IOContext's thread - safe to use Session
session->send_message(&order); // Safe
});
Async Operations#
// Can be called from any thread
session->async_login("", 0, std::chrono::milliseconds(2000),
[](std::uint64_t seq, const std::error_code& ec) {
// Callback runs on IOContext's thread
if (!ec) {
std::cout << "Logged in with sequence: " << seq << std::endl;
}
});
Error Handling#
Check Send Result#
std::error_code ec = session.send_message(&order);
if (ec) {
std::cerr << "Failed to send order: " << ec.message() << std::endl;
}
Handle Rejected Orders#
void on_rejected(Session* s, std::uint64_t seq, const Rejected* msg) {
std::cerr << "Order rejected: UserRefNum=" << msg->get_user_ref_num()
<< " Reason=" << static_cast<int>(msg->get_reason()) << std::endl;
}