File size: 5,979 Bytes
ba6114e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#pragma once
#include "core/simulator.hpp"
#include "core/types.hpp"
#include <string>
#include <sstream>
#include <iomanip>

namespace hft {

struct J {
    static std::string str(const std::string& s) {
        std::ostringstream o; o << "\"";
        for (char c : s) {
            if (c == '"') o << "\\\"";
            else if (c == '\\') o << "\\\\";
            else o << c;
        }
        o << "\""; return o.str();
    }
    static std::string num(double v, int prec = 4) {
        std::ostringstream o; o << std::fixed << std::setprecision(prec) << v; return o.str();
    }
    static std::string num(int64_t v)  { return std::to_string(v); }
    static std::string num(uint64_t v) { return std::to_string(v); }
    static std::string boolean(bool b) { return b ? "true" : "false"; }
};

inline std::string order_to_json(const Order& o) {
    return "{\"id\":"         + J::num(o.id) +
           ",\"symbol\":"     + J::str(o.symbol) +
           ",\"side\":"       + J::str(o.side == Side::BUY ? "BUY" : "SELL") +
           ",\"type\":"       + J::str([&]{ switch(o.type){
               case OrderType::LIMIT:  return "LIMIT";
               case OrderType::MARKET: return "MARKET";
               case OrderType::IOC:    return "IOC";
               case OrderType::FOK:    return "FOK";
           } return "LIMIT"; }()) +
           ",\"price\":"      + J::num(from_price(o.price)) +
           ",\"qty\":"        + J::num(o.qty) +
           ",\"filled_qty\":" + J::num(o.filled_qty) +
           ",\"status\":"     + J::str([&]{ switch(o.status){
               case OrderStatus::PENDING:          return "PENDING";
               case OrderStatus::NEW:              return "NEW";
               case OrderStatus::PARTIALLY_FILLED: return "PARTIALLY_FILLED";
               case OrderStatus::FILLED:           return "FILLED";
               case OrderStatus::CANCELLED:        return "CANCELLED";
               case OrderStatus::REJECTED:         return "REJECTED";
               case OrderStatus::EXPIRED:          return "EXPIRED";
           } return "UNKNOWN"; }()) +
           ",\"timestamp\":"  + J::num(o.timestamp) + "}";
}

inline std::string trade_to_json(const Trade& t) {
    return "{\"trade_id\":"      + J::num(t.trade_id) +
           ",\"buy_order_id\":"  + J::num(t.buy_order_id) +
           ",\"sell_order_id\":" + J::num(t.sell_order_id) +
           ",\"symbol\":"        + J::str(t.symbol) +
           ",\"price\":"         + J::num(from_price(t.price)) +
           ",\"qty\":"           + J::num(t.qty) +
           ",\"timestamp\":"     + J::num(t.timestamp) + "}";
}

inline std::string snapshot_to_json(const OrderBookSnapshot& s, int depth = 10) {
    std::string bids = "[";
    for (int i = 0; i < (int)s.bids.size() && i < depth; ++i) {
        if (i) bids += ",";
        bids += "{\"price\":" + J::num(from_price(s.bids[i].price)) +
                ",\"qty\":"   + J::num(s.bids[i].qty) +
                ",\"orders\":" + J::num((int64_t)s.bids[i].order_count) + "}";
    }
    bids += "]";
    std::string asks = "[";
    for (int i = 0; i < (int)s.asks.size() && i < depth; ++i) {
        if (i) asks += ",";
        asks += "{\"price\":" + J::num(from_price(s.asks[i].price)) +
                ",\"qty\":"   + J::num(s.asks[i].qty) +
                ",\"orders\":" + J::num((int64_t)s.asks[i].order_count) + "}";
    }
    asks += "]";
    return "{\"symbol\":"    + J::str(s.symbol) +
           ",\"timestamp\":" + J::num(s.timestamp) +
           ",\"best_bid\":"  + J::num(from_price(s.best_bid())) +
           ",\"best_ask\":"  + J::num(from_price(s.best_ask())) +
           ",\"mid\":"       + J::num(from_price(s.mid())) +
           ",\"spread\":"    + J::num(s.spread(), 6) +
           ",\"bids\":"      + bids +
           ",\"asks\":"      + asks + "}";
}

inline std::string position_to_json(const Position& p) {
    return "{\"symbol\":"         + J::str(p.symbol) +
           ",\"net_qty\":"        + J::num(p.net_qty) +
           ",\"avg_price\":"      + J::num(p.avg_price) +
           ",\"realized_pnl\":"   + J::num(p.realized_pnl) +
           ",\"unrealized_pnl\":" + J::num(p.unrealized_pnl) +
           ",\"notional\":"       + J::num(p.notional()) + "}";
}

inline std::string backtest_result_to_json(const BacktestResult& r) {
    std::string equity = "[";
    for (size_t i = 0; i < r.equity_curve.size(); ++i) {
        if (i) equity += ",";
        equity += J::num(r.equity_curve[i]);
    }
    equity += "]";
    std::string trades_str = "[";
    for (size_t i = 0; i < r.trades.size() && i < 500; ++i) {
        if (i) trades_str += ",";
        trades_str += trade_to_json(r.trades[i]);
    }
    trades_str += "]";
    return "{\"strategy\":"        + J::str(r.strategy_name) +
           ",\"ticks_processed\":" + J::num(r.ticks_processed) +
           ",\"orders_submitted\":" + J::num(r.orders_submitted) +
           ",\"orders_filled\":"   + J::num(r.orders_filled) +
           ",\"orders_rejected\":" + J::num(r.orders_rejected) +
           ",\"trades_count\":"    + J::num(r.trades_count) +
           ",\"total_pnl\":"       + J::num(r.total_pnl) +
           ",\"realized_pnl\":"    + J::num(r.realized_pnl) +
           ",\"unrealized_pnl\":"  + J::num(r.unrealized_pnl) +
           ",\"max_drawdown\":"    + J::num(r.max_drawdown) +
           ",\"sharpe\":"          + J::num(r.sharpe) +
           ",\"order_p50_us\":"    + J::num(r.order_latency.p50_ns / 1000.0) +
           ",\"order_p99_us\":"    + J::num(r.order_latency.p99_ns / 1000.0) +
           ",\"order_avg_us\":"    + J::num(r.order_latency.avg_us()) +
           ",\"tick_p50_us\":"     + J::num(r.tick_latency.p50_ns / 1000.0) +
           ",\"tick_p99_us\":"     + J::num(r.tick_latency.p99_ns / 1000.0) +
           ",\"throughput_eps\":"  + J::num(r.throughput_eps) +
           ",\"equity_curve\":"    + equity +
           ",\"trades\":"          + trades_str + "}";
}

} // namespace hft