Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e39313ecf6 | ||
|
|
8095100bee |
No files matched your search
@@ -4,6 +4,8 @@ using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using Google.Protobuf;
|
||||
using security_key = System.UInt32;
|
||||
using bts.co2;
|
||||
using System.Linq;
|
||||
|
||||
namespace mbts.co2
|
||||
{
|
||||
@@ -85,6 +87,7 @@ namespace mbts.co2
|
||||
|
||||
[DllImport("libspark")]
|
||||
internal unsafe static extern void post_on_scan_security_thread(Action callback);
|
||||
|
||||
}
|
||||
|
||||
internal static class Co2NativeTestMethods
|
||||
@@ -133,5 +136,59 @@ namespace mbts.co2
|
||||
[DllImport("libspark")]
|
||||
internal static extern void co2_test_get_constants(out ulong max_depth, out ulong max_implied_depth, out sbyte nan_exponent);
|
||||
|
||||
internal unsafe delegate void raw_receive_pb_or_string(byte* buffer, int buffer_size);
|
||||
[DllImport("libspark")]
|
||||
private static unsafe extern void raw_co2_compute_synthetic_book(
|
||||
byte[] security_buffer,
|
||||
int security_length,
|
||||
IntPtr[] leg_books,
|
||||
int[] leg_lengths,
|
||||
int leg_books_length,
|
||||
raw_receive_pb_or_string callback);
|
||||
|
||||
internal static unsafe BookMessageImmutable co2_compute_synthetic_book(SecurityImmutable synthetic, params BookMessageImmutable[] books) {
|
||||
BookMessage result = null;
|
||||
string error = null;
|
||||
|
||||
var security_buffer = synthetic.ToByteArray();
|
||||
// var h = GCHandle.Alloc(null, GCHandleType.Pinned).
|
||||
var book_buffers =
|
||||
books
|
||||
.Select(b => b.ToByteArray())
|
||||
.ToArray();
|
||||
GCHandle[] book_buffer_handles =
|
||||
book_buffers
|
||||
.Select(b => GCHandle.Alloc(b,GCHandleType.Pinned))
|
||||
.ToArray();
|
||||
IntPtr[] book_buffer_pointers =
|
||||
book_buffer_handles
|
||||
.Select(h => h.AddrOfPinnedObject())
|
||||
.ToArray();
|
||||
var lengths =
|
||||
book_buffers
|
||||
.Select(b => b.Length)
|
||||
.ToArray();
|
||||
|
||||
raw_co2_compute_synthetic_book(
|
||||
security_buffer,
|
||||
security_buffer.Length,
|
||||
book_buffer_pointers,
|
||||
lengths,
|
||||
book_buffers.Length,
|
||||
(byte* buffer, int length) => {
|
||||
if (length < 0) {
|
||||
error = new string((char*)buffer,0,-1 * length);
|
||||
}
|
||||
else {
|
||||
result = Co2NativeMethods.deserialize<BookMessage>(buffer, (ulong)length);
|
||||
}
|
||||
});
|
||||
|
||||
if(error != null) {
|
||||
// C# style multiple return values
|
||||
throw new Exception(error);
|
||||
}
|
||||
return new BookMessageImmutable(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +52,17 @@ namespace mbts.co2 {
|
||||
return _mantissa.GetHashCode();
|
||||
}
|
||||
|
||||
public static IntPrice from_double(double price, sbyte precision) {
|
||||
if (double.IsNaN(price)) return NaN;
|
||||
if (Math.Abs(price%1) != 0) {
|
||||
double rounding = 0.5 * Math.Pow(10,-precision);
|
||||
price += (price > 0) ? rounding : -rounding;
|
||||
price *= Math.Pow(10,precision);
|
||||
return new IntPrice((long)price, (sbyte)-precision);
|
||||
}
|
||||
return new IntPrice((long)price, 0);
|
||||
}
|
||||
|
||||
public static IntPrice NaN = new IntPrice(0,127);
|
||||
}
|
||||
|
||||
|
||||
@@ -286,6 +286,46 @@ namespace mbts.co2.tests
|
||||
assert_about_equal(dt_utc_now.Second, DateTime.UtcNow.Second);
|
||||
}
|
||||
|
||||
[Test,Ignore("Sample code")]
|
||||
public void merge_synthetic_book() {
|
||||
Security security = new Security();
|
||||
PriceSizeMessage mkPriceSize(double price, UInt32 size) {
|
||||
var iprice = IntPrice.from_double(price, 11);
|
||||
return new PriceSizeMessage() {
|
||||
Mantissa = iprice.mantissa,
|
||||
Exponent = iprice.exponent,
|
||||
Size = size
|
||||
};
|
||||
}
|
||||
IEnumerable<PriceSizeMessage> mkPrices(params (double,uint)[] args) {
|
||||
return args.Select((ps) => mkPriceSize(ps.Item1,ps.Item2));
|
||||
}
|
||||
var leg1 = new BookMessage() {
|
||||
Bids = {
|
||||
mkPriceSize(2000, 10),
|
||||
mkPriceSize(1999.75, 5),
|
||||
mkPriceSize(1999.5, 7)
|
||||
},
|
||||
Asks = {
|
||||
mkPriceSize(2000.25,15),
|
||||
mkPriceSize(2000.5, 5),
|
||||
mkPriceSize(2001,10)
|
||||
}
|
||||
}.immutable();
|
||||
var leg2 = new BookMessage() {
|
||||
Bids = {
|
||||
mkPrices( (2003, 5), (2002.75, 15), (2002.5, 12))
|
||||
},
|
||||
Asks = {
|
||||
mkPrices( (2003.25, 12), (2003.5, 3), (2003.75,5))
|
||||
}
|
||||
}.immutable();
|
||||
|
||||
var result = Co2NativeTestMethods.co2_compute_synthetic_book(security.immutable(), leg1, leg2);
|
||||
Assert.IsTrue(result.Bids.First().Size == 5);
|
||||
Assert.IsTrue(result.Asks.First().Size == 2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lib/config/config.h"
|
||||
#include "lib/md/protos/co2.pb.h"
|
||||
#include "lib/utils/TimeStamp.h"
|
||||
#include "lib/md/test/md_test_utils.h"
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
@@ -15,7 +16,7 @@ using namespace co2;
|
||||
|
||||
std::vector<MDProducerHandle> create_test_securities(MDProducer& producer, const char* postfix = "M");
|
||||
|
||||
void assign_ids(std::vector<MDProducerHandle>::iterator begin, std::vector<MDProducerHandle>::iterator end, security_key start_key = 1000);
|
||||
// void assign_ids(std::vector<MDProducerHandle>::iterator begin, std::vector<MDProducerHandle>::iterator end, security_key start_key = 1000);
|
||||
|
||||
extern "C" BTS_EXPORT void co2_get_1234_handle(size_t& size, MDConsumerHandle& handle, uintptr_t* hotaddr, uintptr_t* coldaddr, uintptr_t* headeraddr) {
|
||||
// Test that marshaling is working
|
||||
@@ -169,5 +170,72 @@ extern "C" BTS_EXPORT void co2_get_sample_datetime(datetime::LLDateTime& now, da
|
||||
utc_now = datetime::ll_now();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Book compute_synthetic_book(const api::Security& security, const std::vector<Book>& leg_books);
|
||||
|
||||
typedef void(*raw_receive_pb_or_string)(const char*, int);
|
||||
extern "C" BTS_EXPORT void raw_co2_compute_synthetic_book(
|
||||
const char* security_buffer,
|
||||
int security_len,
|
||||
const char** book_buffers,
|
||||
const int* book_lengths,
|
||||
int book_buffers_length,
|
||||
raw_receive_pb_or_string cb) {
|
||||
|
||||
// Deserialize Security
|
||||
api::Security security;
|
||||
if (!security.ParseFromArray(security_buffer, security_len)) {
|
||||
const char* err = "Security parse error";
|
||||
cb(err, -1 * strlen(err));
|
||||
return;
|
||||
}
|
||||
|
||||
// Deserialize BookMessage and convert to Book
|
||||
std::vector<Book> books;
|
||||
for (int x = 0; x < book_buffers_length; ++x) {
|
||||
BookMessage bm;
|
||||
if (!bm.ParseFromArray(book_buffers[x], book_lengths[x])) {
|
||||
auto err = fmt::format("Book parse error: {}", x);
|
||||
cb(err.c_str(), -1 * err.size());
|
||||
return;
|
||||
}
|
||||
Book book;
|
||||
for (const auto& bid : bm.bids()) {
|
||||
IntPrice ip { bid.mantissa(), (int8_t)bid.exponent() };
|
||||
book.bids.push_back({ ip.price(), bid.size() });
|
||||
}
|
||||
for (const auto& ask : bm.asks()) {
|
||||
IntPrice ip { ask.mantissa(), (int8_t)ask.exponent() };
|
||||
book.asks.push_back({ ip.price(), ask.size() });
|
||||
}
|
||||
books.push_back(book);
|
||||
}
|
||||
|
||||
// Make the call we wanted to make in the first place
|
||||
Book bres = compute_synthetic_book(security, books);
|
||||
|
||||
// Copy back to a BookMessage
|
||||
BookMessage bmres;
|
||||
for (const auto & bid : bres.bids) {
|
||||
PriceSizeMessage& ps = *bmres.add_bids();
|
||||
auto ip = IntPrice_from_double<11>(bid.price);
|
||||
ps.set_mantissa(ip.mantissa());
|
||||
ps.set_exponent(ip.exponent());
|
||||
ps.set_size(bid.size);
|
||||
}
|
||||
for (const auto & ask : bres.asks) {
|
||||
PriceSizeMessage& ps = *bmres.add_asks();
|
||||
auto ip = IntPrice_from_double<11>(ask.price);
|
||||
ps.set_mantissa(ip.mantissa());
|
||||
ps.set_exponent(ip.exponent());
|
||||
ps.set_size(ask.size);
|
||||
}
|
||||
|
||||
// serialize to string
|
||||
auto str = bmres.SerializeAsString();
|
||||
cb(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
}}}//namespace
|
||||
#endif
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "md_test_utils.h"
|
||||
#include "../MDProducer.h"
|
||||
#include "lib/utils/sane_algorithm.h"
|
||||
#include "../MDConsumerHandle.h"
|
||||
#include "Co2TestInstrument.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
@@ -38,4 +41,49 @@ void assign_ids(std::vector<MDProducerHandle>::iterator begin, std::vector<MDPro
|
||||
}
|
||||
}
|
||||
|
||||
Book compute_synthetic_book(const api::Security& security, const std::vector<Book>& leg_books) {
|
||||
auto synthetic = std::make_shared<SyntheticStrategy>();
|
||||
synthetic->security.CopyFrom(security);
|
||||
std::vector<Co2TestInstrument> leg_instruments;
|
||||
for (const auto& leg : synthetic->security.synthetic().legs()) {
|
||||
const auto& security = leg.security();
|
||||
Co2TestInstrument instr(security.symbol(), securitytype_of(security));
|
||||
convert_security(security, instr.cold().security, true);
|
||||
leg_instruments.push_back(instr);
|
||||
synthetic->legs.push_back(instr.consumer());
|
||||
}
|
||||
|
||||
// Write leg books
|
||||
for (size_t x = 0; x < leg_books.size(); ++x) {
|
||||
std::array<PriceSize,COCONUT_MAX_DEPTH> bids = {}, asks = {};
|
||||
std::transform(
|
||||
leg_books[x].bids.begin(),
|
||||
leg_books[x].bids.end(),
|
||||
bids.begin(),
|
||||
[](const PS& ps) {
|
||||
return PriceSize_from_double<7>(ps.price, ps.size);
|
||||
});
|
||||
std::transform(
|
||||
leg_books[x].asks.begin(),
|
||||
leg_books[x].asks.end(),
|
||||
asks.begin(),
|
||||
[](const PS& ps) {
|
||||
return PriceSize_from_double<7>(ps.price, ps.size);
|
||||
});
|
||||
auto ts = TimeStamp::now();
|
||||
leg_instruments[x].producer().update_direct(ts, bids, asks);
|
||||
}
|
||||
|
||||
// Read synthetic book back
|
||||
MDConsumerHandle synthetic_handle { synthetic };
|
||||
std::array<PriceSize,COCONUT_MAX_DEPTH> raw_bids, raw_asks;
|
||||
TimeStamp t;
|
||||
synthetic_handle.get_direct_book(t, COCONUT_MAX_DEPTH, raw_bids.data(), raw_asks.data());
|
||||
Book result {};
|
||||
sane::map(raw_bids, result.bids, [](PriceSize ps) -> PS { return {ps.price(), ps.size()}; });
|
||||
sane::map(raw_asks, result.asks, [](PriceSize ps) -> PS { return {ps.price(), ps.size()}; });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}}}//namespace
|
||||
@@ -142,50 +142,6 @@ void set_leg_params(SyntheticStrategy& strat, uint32_t security_key, const spark
|
||||
}
|
||||
|
||||
|
||||
Book compute_synthetic_book(const api::Security& security, const std::vector<Book>& leg_books) {
|
||||
auto synthetic = std::make_shared<SyntheticStrategy>();
|
||||
synthetic->security.CopyFrom(security);
|
||||
vector<Co2TestInstrument> leg_instruments;
|
||||
for (const auto& leg : synthetic->security.synthetic().legs()) {
|
||||
const auto& security = leg.security();
|
||||
Co2TestInstrument instr(security.symbol(), securitytype_of(security));
|
||||
convert_security(security, instr.cold().security, true);
|
||||
leg_instruments.push_back(instr);
|
||||
synthetic->legs.push_back(instr.consumer());
|
||||
}
|
||||
|
||||
// Write leg books
|
||||
for (size_t x = 0; x < leg_books.size(); ++x) {
|
||||
std::array<PriceSize,COCONUT_MAX_DEPTH> bids = {}, asks = {};
|
||||
std::transform(
|
||||
leg_books[x].bids.begin(),
|
||||
leg_books[x].bids.end(),
|
||||
bids.begin(),
|
||||
[](const PS& ps) {
|
||||
return PriceSize_from_double<7>(ps.price, ps.size);
|
||||
});
|
||||
std::transform(
|
||||
leg_books[x].asks.begin(),
|
||||
leg_books[x].asks.end(),
|
||||
asks.begin(),
|
||||
[](const PS& ps) {
|
||||
return PriceSize_from_double<7>(ps.price, ps.size);
|
||||
});
|
||||
auto ts = TimeStamp::now();
|
||||
leg_instruments[x].producer().update_direct(ts, bids, asks);
|
||||
}
|
||||
|
||||
// Read synthetic book back
|
||||
MDConsumerHandle synthetic_handle { synthetic };
|
||||
std::array<PriceSize,COCONUT_MAX_DEPTH> raw_bids, raw_asks;
|
||||
TimeStamp t;
|
||||
synthetic_handle.get_direct_book(t, COCONUT_MAX_DEPTH, raw_bids.data(), raw_asks.data());
|
||||
Book result {};
|
||||
sane::map(raw_bids, result.bids, [](PriceSize ps) -> PS { return {ps.price(), ps.size()}; });
|
||||
sane::map(raw_asks, result.asks, [](PriceSize ps) -> PS { return {ps.price(), ps.size()}; });
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// Test Cases
|
||||
|
||||
Reference in new issue
Block a user