Compare commits

...
42 Commits
rm ... ml
Author SHA1 Message Date
Kevin Darby cbf1fad2dd Merge branch 'master' of bitbucket.org:bluetradesys/spark into ml 2019-02-11 11:30:08 -05:00
Kevin Darby 1fbc1584e5 Merge branch 'algos2' of bitbucket.org:bluetradesys/spark into ml 2019-02-08 17:19:16 -05:00
Kevin Darby 02defef93d oco testing 2019-02-08 14:55:16 -05:00
Kevin Darby 9390fb0639 per Brian standardizing on Stop Ticks, Stop Type, Profit Ticks, Profit Type 2019-02-06 17:41:24 -05:00
Kevin Darby 6d774d46c9 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-02-05 17:51:13 -05:00
Kevin Darby b39812aad0 add RelativeSide enum for OCO. Fix SPARK-2022 2019-02-05 17:50:08 -05:00
Kevin Darby f99717d880 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-02-05 10:03:16 -05:00
Kevin Darby f224b8be43 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-02-04 16:57:05 -05:00
Kevin Darby f5457e5ce4 Merge branch 'master' of bitbucket.org:bluetradesys/spark into ml 2019-01-23 13:45:26 -05:00
Kevin Darby 5ba746fd59 small merge issue 2019-01-22 16:31:11 -05:00
Kevin Darby ab5cb23062 Merge branch 'algos2' of bitbucket.org:bluetradesys/spark into ml 2019-01-22 16:11:28 -05:00
Kevin Darby 4ebdc603c5 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2019-01-22 16:10:38 -05:00
Kevin Darby f4b7fbe6b5 didn't save 2019-01-11 16:05:57 -05:00
Kevin Darby 9901ef54d4 working on execution 2019-01-11 16:05:37 -05:00
Kevin Darby 293c13e11d we can load tf models in spark orders. Now we need to be able to execute them 2019-01-11 14:42:56 -05:00
Kevin Darby be4c69fad4 libtf 2019-01-10 23:45:37 -05:00
Kevin Darby 2c4dc8fbe5 externals 2019-01-10 18:23:22 -05:00
Kevin Darby 4ea93bc386 just needs some rpath and I'm in business 2019-01-10 18:22:03 -05:00
Kevin Darby 1c6333b07a now I have to figure out how to load the model 2019-01-09 18:15:04 -05:00
Kevin Darby 26d543af82 long journey with externals 2019-01-08 09:57:53 -05:00
Kevin Darby 99b301ad6f statically linking tf with sparklib 2019-01-07 23:00:56 -05:00
Kevin Darby 9cbe83e1a4 keep tf out in the sdk land for a bit 2019-01-07 18:32:36 -05:00
Kevin Darby 59369e1b2b moving towards a tflow example 2019-01-07 17:54:39 -05:00
Kevin Darby 7c42e75ddd getting close 2019-01-04 18:14:53 -05:00
Kevin Darby b453be40fe strings... 2019-01-03 18:11:13 -05:00
Kevin Darby 96709c8121 ai algo sample 2019-01-03 16:20:15 -05:00
Kevin Darby 5de9f63665 new proto36 2019-01-02 17:14:00 -05:00
Kevin Darby 6089b209d1 we want caffe2 in c++ not libtorch 2018-12-28 23:09:30 -05:00
Kevin Darby d7a12d0dd9 checkpoint 2018-12-28 17:40:32 -05:00
Kevin Darby 2f87fe31be mlpack 2018-12-21 18:25:19 -05:00
Kevin Darby 5a9749d551 testing this out in the sdk 2018-12-21 17:17:18 -05:00
Kevin Darby ea950c8786 pushed by mistake 2018-12-21 17:05:24 -05:00
Kevin Darby 30891bfb49 need a little boost 2018-12-21 15:28:45 -05:00
Kevin Darby 34319c4536 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-20 16:10:58 -05:00
Kevin Darby 196c518ac6 remove tick order 2018-12-20 09:43:44 -05:00
Kevin Darby f04af5af9d fix build 2018-12-20 09:39:05 -05:00
Kevin Darby 8f4da463a7 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-19 18:24:14 -05:00
Kevin Darby f3adf780d0 OCOOrder will be the basis of a StopLoss template
Added the beginnings of pricer order but need something from John
2018-12-19 18:15:04 -05:00
Kevin Darby 664c1f28ed Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-17 18:05:59 -05:00
Kevin Darby aae927d773 gui for new algos 2018-12-17 17:38:22 -05:00
Kevin Darby 00dba92636 Merge branch 'master' of bitbucket.org:bluetradesys/spark into algos2 2018-12-17 15:36:32 -05:00
Kevin Darby 5a5de65292 OCO and Pricer Algos 2018-12-17 13:56:24 -05:00
43 changed files with 2032 additions and 578 deletions

No files matched your search

+3
View File
@@ -30,6 +30,7 @@
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/linux/include/tensorflow/contrib/makefile/gen/proto",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
@@ -50,6 +51,7 @@
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/linux/include/tensorflow/contrib/makefile/gen/proto",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
@@ -74,6 +76,7 @@
"${workspaceRoot}/build/ninja_debug/src",
"${workspaceRoot}/externals/windows/include",
"${workspaceRoot}/externals/linux/include",
"${workspaceRoot}/externals/linux/include/tensorflow/contrib/makefile/gen/proto",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/x86_64-linux-gnu/c++/6",
"${workspaceRoot}/externals/windows/vscode/usr/include/c++/6/backward",
+41 -1
View File
@@ -6,7 +6,7 @@
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/build/ninja_debug/src/server/sparkd/sparkd",
"program": "${workspaceRoot}/build/ninja_debug/server/sparkd/sparkd",
"args": ["run"],
"stopAtEntry": false,
"cwd": "${workspaceRoot}/build/ninja_debug/src/server/sparkd",
@@ -108,6 +108,46 @@
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "TFTest ",
"type": "cppdbg",
"request": "launch",
"program": "/home/bts/spark/build/ninja_debug/sdk/examples/tf_test",
"args": [
],
"stopAtEntry": false,
"cwd": "/home/bts/spark/build/ninja_debug/sdk/examples/",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"preLaunchTask": "",
"logging": {
"engineLogging": false
},
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "enable pretty-printer",
"ignoreFailures": true
},
{
"description": "Skip STL",
"text": "skip -gfi /usr/include/c++/7/bits/*.h",
"ignoreFailures": true
}
],
"pipeTransport": {
"pipeCwd": "${workspaceRoot}",
"pipeProgram": "c:\\program files\\git\\usr\\bin\\ssh.exe",
"pipeArgs": [
"bts@sparkvm"
],
"debuggerPath": "/usr/bin/gdb"
},
"sourceFileMap": {
"/home/bts/spark/": "${workspaceRoot}"
}
},
{
"name": "Spreader Tests",
"type": "cppdbg",
+4 -1
View File
@@ -13,7 +13,7 @@ set (SPARK_BIN "${EXTERNALS_ROOT}/bin")
set (SPARK_INCLUDE "${EXTERNALS_ROOT}/include")
set (SPARK_LIB "${EXTERNALS_ROOT}/lib/${CMAKE_BUILD_TYPE}")
include_directories (BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib)
include_directories (BEFORE SYSTEM ${SPARK_INCLUDE} ${EXTERNALS_ROOT}/include/zlib ${TF_INCLUDE})
link_directories (${SPARK_LIB})
if (WIN32)
@@ -57,6 +57,9 @@ else ()
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/src/lib/libspark.so ${CMAKE_BINARY_DIR}/server
COMMAND mkdir ARGS -p ${CMAKE_BINARY_DIR}/server/plugins
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
COMMAND ln ARGS -sf ${CMAKE_BINARY_DIR}/sdk/examples/ai_order_plugin_example.so ${CMAKE_BINARY_DIR}/server/plugins/
COMMAND ln ARGS -sf ${EXTERNALS_ROOT}/lib/Release/libtensorflow.so ${CMAKE_BINARY_DIR}/server/plugins
COMMENT "Creating server runtime layout"
DEPENDS sparkd data_files_dir)
+27
View File
@@ -0,0 +1,27 @@
{
"folders": [
{
"path": "."
},
{
"uri": "sftp://bts:BT5u53r@sparkvm:22/home/bts/",
"name": "sparkvm"
}
],
"settings": {
"files.associations": {
"utility": "cpp",
"initializer_list": "cpp",
"list": "cpp",
"type_traits": "cpp",
"vector": "cpp",
"xhash": "cpp",
"xstring": "cpp",
"system_error": "cpp",
"array": "cpp",
"string_view": "cpp",
"xutility": "cpp",
"*.ipp": "cpp"
}
}
}
+77
View File
@@ -0,0 +1,77 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"files.associations": {
"utility": "cpp",
"initializer_list": "cpp",
"list": "cpp",
"type_traits": "cpp",
"vector": "cpp",
"xhash": "cpp",
"xstring": "cpp",
"system_error": "cpp",
"array": "cpp",
"string_view": "cpp",
"xutility": "cpp",
"*.ipp": "cpp",
"atomic": "cpp",
"hash_map": "cpp",
"hash_set": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"cfenv": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"exception": "cpp",
"any": "cpp",
"optional": "cpp",
"fstream": "cpp",
"functional": "cpp",
"future": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"numeric": "cpp",
"ratio": "cpp",
"scoped_allocator": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"tuple": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp"
}
}
}
@@ -25,6 +25,8 @@ namespace mbts.ui.spark {
public DataTemplate JoinOrderTemplate { get; set; }
public DataTemplate TopOrderTemplate { get; set; }
public DataTemplate CoverOrderTemplate { get; set; }
public DataTemplate OCOOrderTemplate { get; set; }
public DataTemplate PricerOrderTemplate { get; set; }
public DataTemplate OffsetOrderTemplate { get; set; }
public DataTemplate TriggerOrderTemplate { get; set; }
public DataTemplate IcebergOrderTemplate { get; set; }
@@ -43,6 +45,8 @@ namespace mbts.ui.spark {
case CustomOrderDefinition.CustomOneofCase.Join: return JoinOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Top: return TopOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Cover: return CoverOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Oco : return OCOOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Pricer: return PricerOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Offset: return OffsetOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Trigger: return TriggerOrderTemplate;
case CustomOrderDefinition.CustomOneofCase.Iceberg: return IcebergOrderTemplate;
@@ -126,6 +126,8 @@ namespace mbts.spark
return _child_order_choices;
}
}
public bool has_child => _order_def_tags.Any();
public IOrderTypeVM child_order
{
@@ -0,0 +1,257 @@
using bts.api;
using bts.api.orderman;
using mbts.ui;
using mbts.ui.utility;
using mbts.utils;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using static bts.api.orderman.CustomOrderDefinition;
namespace mbts.spark
{
static partial class OrderTypeVMFactory
{
class InlineOCOOrderProperties
{
public InlineOCOOrderProperties(OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
var othertype = CustomOneofCase.Limit;
this.selected_other_order_type = new InlineUserProperty<OrderTemplateHeader>(new OrderTemplateHeader(othertype), true);
this.other_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
other_ticks = new InlineUserProperty<int>(1, false);
other_side = new InlineUserProperty<bts.api.RelativeSide>(bts.api.RelativeSide.Same, false);
}
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<OrderTemplateHeader> selected_other_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> other_order_types;
public readonly InlineUserProperty<int> other_ticks;
public readonly InlineUserProperty<bts.api.RelativeSide> other_side;
}
class OCOOrderVM : OrderTypeVMBase<OCOOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineOCOOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _other_order_choices;
IOrderTypeVM _other_order;
IDisposable _other_order_errors_sub;
public int other_ticks { get; set; } = 1;
public bts.api.RelativeSide other_side { get; set; } = bts.api.RelativeSide.Same;
public OCOOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineOCOOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name)
{ }
public OCOOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineOCOOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
security_md_source.OnDispatcher()
.Subscribe(smd => _security = smd.security),
inline_properties.OnDispatcher()
.Subscribe(p =>
{
if (_order_types.Count == 0 || p.child_order_types.force_override)
{
_order_types.SetItems(p.child_order_types.value);
}
if (_child_order_choices != null && (_child_order == null || p.selected_child_order_type.force_override))
{
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (_other_order_choices != null && (_other_order == null || p.selected_other_order_type.force_override))
{
_select_other_order(p.selected_other_order_type.value.key.type);
}
if (p.other_ticks.force_override)
{
other_ticks = p.other_ticks.value;
RaisePropertyChanged(nameof(other_ticks));
}
if (p.other_side.force_override)
{
other_side = p.other_side.value;
RaisePropertyChanged(nameof(other_side));
}
_inline_props = p;
_validate();
})
);
_validate();
}
public override void assign_to(CustomOrderDefinition value)
{
if (_child_order == null)
_select_child_order(model.factory.default_order_type(_security.Value, true));
if (_other_order == null )
_select_other_order(model.factory.default_order_type(_security.Value, true));
_validate();
if (!HasErrors)
{
var i = factory.oco_order();
i.OtherTicks = other_ticks;
i.OtherSide = other_side;
child_order.assign_to(i.Child);
if (other_order != null)
other_order.assign_to(i.Other);
value.Oco = i;
}
}
public IEnumerable<bts.api.RelativeSide> other_side_types => EnumHelper.get_values_except<bts.api.RelativeSide>(bts.api.RelativeSide.Undefined);
public ICollection<IOrderTypeVM> child_order_types
{
get
{
if (_child_order_choices == null)
_child_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _child_order_choices;
}
}
public ICollection<IOrderTypeVM> other_order_types
{
get
{
if (_other_order_choices == null)
_other_order_choices = new ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader>(_order_types, ot => create(ot.key.type, ot.key.name, ot.display_name, model, _security_md_source));
return _other_order_choices;
}
}
public IOrderTypeVM child_order
{
get
{
init();
return _child_order;
}
set
{
Disposable.dispose(ref _child_order_errors_sub);
_child_order = value;
_child_order?.init();
if (_child_order is INotifyDataErrorInfo ndei)
{
ndei.ErrorsChanged += on_errors_changed;
void on_errors_changed(object s, DataErrorsChangedEventArgs e) =>
_validate();
_child_order_errors_sub = Disposable.Create(() => ndei.ErrorsChanged -= on_errors_changed);
}
_validate();
RaisePropertyChanged(nameof(child_order));
}
}
public IOrderTypeVM other_order
{
get
{
init();
return _other_order;
}
set
{
Disposable.dispose(ref _other_order_errors_sub);
_other_order = value;
_other_order?.init();
if (_other_order is INotifyDataErrorInfo ndei)
{
ndei.ErrorsChanged += on_errors_changed;
void on_errors_changed(object s, DataErrorsChangedEventArgs e) =>
_validate();
_other_order_errors_sub = Disposable.Create(() => ndei.ErrorsChanged -= on_errors_changed);
}
_validate();
RaisePropertyChanged(nameof(other_order));
}
}
public void Dispose()
{
Disposable.dispose(ref _dispose);
if (_child_order_choices != null)
_child_order_choices.OfType<IDisposable>().DisposeAll();
if (_other_order_choices != null)
_other_order_choices.OfType<IDisposable>().DisposeAll();
}
public override void init()
{
if (_child_order == null && _security.HasValue)
_select_child_order();
if (_other_order == null && _security.HasValue)
_select_other_order();
_validate();
}
void _select_child_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_child_order_type.has_value ?
_inline_props.selected_child_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_child_order(ot);
}
void _select_child_order(CustomOneofCase ot)
{
_child_order = child_order_types.FirstOrDefault(vm => vm.order_type == ot);
if (_child_order == null)
_child_order = child_order_types.FirstOrDefault();
RaisePropertyChanged(nameof(child_order));
}
void _select_other_order()
{
CustomOneofCase ot = _inline_props != null && _inline_props.selected_other_order_type.has_value ?
_inline_props.selected_other_order_type.value.key.type :
model.factory.default_order_type(_security.Value, true);
_select_other_order(ot);
}
void _select_other_order(CustomOneofCase ot)
{
_other_order = other_order_types.FirstOrDefault(vm => vm.order_type == ot);
if (_other_order == null)
_other_order = other_order_types.FirstOrDefault();
RaisePropertyChanged(nameof(other_order));
}
void _validate()
{
if (_child_order == null || (_child_order is INotifyDataErrorInfo ndei && ndei.HasErrors))
set_error(nameof(child_order), string.Empty, true);
else clear_error(nameof(child_order));
if ((_other_order == null ) || (_other_order is INotifyDataErrorInfo hdei && hdei.HasErrors))
set_error(nameof(other_order), string.Empty, true);
else clear_error(nameof(other_order));
}
}
}
}
@@ -15,11 +15,12 @@ namespace mbts.spark {
public static IOrderTypeVM stop(OrdersModel model, string id, string display_name) => new StopOrderVM(model, id, display_name);
public static IOrderTypeVM stop_limit(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new StopLimitOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM time_box(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TimeBoxOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM tick(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TickOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM lean(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new LeanOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM join(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new JoinOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM top(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TopOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM cover(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new CoverOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM oco(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new OCOOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM pricer(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new PricerOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM offset(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new OffsetOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM trigger(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new TriggerOrderVM(model, security_md_source, id, display_name);
public static IOrderTypeVM iceberg(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name) => new IcebergOrderVM(model, security_md_source, id, display_name);
@@ -34,11 +35,12 @@ namespace mbts.spark {
case CustomOneofCase.Stop: return stop(model, id, display_name);
case CustomOneofCase.StopLimit: return stop_limit(model, security_md_source, id, display_name);
case CustomOneofCase.TimeBox: return time_box(model, security_md_source, id, display_name);
case CustomOneofCase.Tick: return tick(model, security_md_source, id, display_name);
case CustomOneofCase.Lean: return lean(model, security_md_source, id, display_name);
case CustomOneofCase.Join: return join(model, security_md_source, id, display_name);
case CustomOneofCase.Top: return top(model, security_md_source, id, display_name);
case CustomOneofCase.Cover: return cover(model, security_md_source, id, display_name);
case CustomOneofCase.Oco : return oco(model, security_md_source, id, display_name);
case CustomOneofCase.Pricer: return pricer(model, security_md_source, id, display_name);
case CustomOneofCase.Offset: return offset(model, security_md_source, id, display_name);
case CustomOneofCase.Trigger: return trigger(model, security_md_source, id, display_name);
case CustomOneofCase.Iceberg: return iceberg(model, security_md_source, id, display_name);
@@ -15,52 +15,42 @@ namespace mbts.spark
{
static partial class OrderTypeVMFactory
{
class InlineTickOrderProperties
class InlinePricerOrderProperties
{
public InlineTickOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
public InlinePricerOrderProperties (OrderTemplateHeader selected_child_order_type, IReadOnlyCollection<OrderTemplateHeader> child_order_types)
{
ExceptionAssert.InvalidOperation.That(child_order_types.Contains(selected_child_order_type), $"Child order type {selected_child_order_type} is not in child_order_types");
this.selected_child_order_type = new InlineUserProperty<OrderTemplateHeader>(selected_child_order_type, true);
this.child_order_types = new InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>>(child_order_types, true);
tick_offset_on_deploy = new InlineUserProperty<uint>(0, false);
cross_threshold = new InlineUserProperty<bts.spark.QuantityMeasure>(
new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1}, false);
cross_ticks = new InlineUserProperty<uint>(0, false);
max_chase_ticks = new InlineUserProperty<uint>(10, false);
detach_on_toward = new InlineUserProperty<bool>(true, false);
price_offset_ticks = new InlineUserProperty<int>(0, false);
price_factor = new InlineUserProperty<double>(0, false);
}
public readonly InlineUserProperty<OrderTemplateHeader> selected_child_order_type;
public readonly InlineUserProperty<IReadOnlyCollection<OrderTemplateHeader>> child_order_types;
public readonly InlineUserProperty<uint> tick_offset_on_deploy;
public readonly InlineUserProperty<bts.spark.QuantityMeasure> cross_threshold;
public readonly InlineUserProperty<uint> cross_ticks;
public readonly InlineUserProperty<uint> max_chase_ticks;
public readonly InlineUserProperty<bool> detach_on_toward;
public readonly InlineUserProperty<int> price_offset_ticks;
public readonly InlineUserProperty<double> price_factor;
}
class TickOrderVM : OrderTypeVMBase<TickOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
class PricerOrderVM : OrderTypeVMBase<PricerOrderDefinition>, IHierarchicalOrderTypeVM, IDisposable
{
readonly IObservable<SecurityMD> _security_md_source;
SecurityImmutable? _security;
ObservableCollection<OrderTemplateHeader> _order_types = new ObservableCollection<OrderTemplateHeader>();
ObservableAutoWrapper<IOrderTypeVM, OrderTemplateHeader> _child_order_choices;
InlineTickOrderProperties _inline_props;
InlinePricerOrderProperties _inline_props;
IOrderTypeVM _child_order;
IDisposable _dispose, _child_order_errors_sub;
public uint tick_offset_on_deploy { get; set; } = 0;
public bts.spark.QuantityMeasure cross_threshold { get; set; } = new bts.spark.QuantityMeasure() { Ratio = 1.0, Absolute = 1 };
public uint cross_ticks { get; set; } = 0;
public uint max_chase_ticks { get; set; } = 10;
public bool detach_on_toward { get; set; } = true;
public int price_offset_ticks { get; set; } = 0;
public double price_factor { get; set; } = 1.0;
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
public PricerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source, string id, string display_name)
: this(model, security_md_source, security_md_source.Select(smd =>
new InlineTickOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
new InlinePricerOrderProperties(new OrderTemplateHeader(model.factory.default_order_type(smd.security)), model.factory.default_order_types(smd.security).Select(t => new OrderTemplateHeader(t)).ToList())), id, display_name) { }
public TickOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlineTickOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
public PricerOrderVM(OrdersModel model, IObservable<SecurityMD> security_md_source,
IObservable<InlinePricerOrderProperties> inline_properties, string id, string display_name) : base(model, id, display_name)
{
_security_md_source = security_md_source;
_dispose = Disposable.Create(
@@ -76,31 +66,16 @@ namespace mbts.spark
{
_select_child_order(p.selected_child_order_type.value.key.type);
}
if (p.tick_offset_on_deploy.force_override)
if (p.price_offset_ticks.force_override)
{
tick_offset_on_deploy = p.tick_offset_on_deploy.value;
RaisePropertyChanged(nameof(tick_offset_on_deploy));
price_offset_ticks = p.price_offset_ticks.value;
RaisePropertyChanged(nameof(price_offset_ticks));
}
if (p.cross_threshold.force_override)
if (p.price_factor.force_override)
{
cross_threshold = p.cross_threshold.value;
RaisePropertyChanged(nameof(cross_threshold));
}
if (p.cross_ticks.force_override)
{
cross_ticks = p.cross_ticks.value;
RaisePropertyChanged(nameof(cross_ticks));
}
if (p.max_chase_ticks.force_override)
{
max_chase_ticks = p.max_chase_ticks.value;
RaisePropertyChanged(nameof(max_chase_ticks));
}
if (p.detach_on_toward.force_override)
{
detach_on_toward = p.detach_on_toward.value;
RaisePropertyChanged(nameof(detach_on_toward));
}
price_factor = p.price_factor.value;
RaisePropertyChanged(nameof(price_factor));
}
_inline_props = p;
_validate();
})
@@ -115,14 +90,11 @@ namespace mbts.spark
_validate();
if (!HasErrors)
{
var i = factory.tick_order();
i.TickOffsetOnDeploy = tick_offset_on_deploy;
i.CrossThreshold = cross_threshold;
i.CrossTicks = cross_ticks;
i.MaxChaseTicks = max_chase_ticks;
i.DetachOnToward = detach_on_toward;
var i = factory.pricer_order();
i.PriceOffsetTicks = price_offset_ticks;
i.PriceFactor = price_factor;
child_order.assign_to(i.Child);
value.Tick = i;
value.Pricer = i;
}
}
@@ -211,6 +211,8 @@ namespace mbts.ui {
public static BTSColor lean_order { get { return new BTSColor(255, 170, 210); } }
public static BTSColor join_order { get { return new BTSColor(200, 171, 232); } }
public static BTSColor cover_order { get { return new BTSColor(134, 232, 224); } }
public static BTSColor oco_order { get { return new BTSColor(110, 94, 11); } }
public static BTSColor pricer_order { get { return new BTSColor(170, 132, 150); } }
public static BTSColor trigger_order { get { return new BTSColor(172, 255, 179); } }
public static BTSColor off_order { get { return new BTSColor(0x8a, 0x00, 0x5f); } }//8a005f
public static BTSColor top_order { get { return new BTSColor(0xdd, 0x7a, 0x27); } }//dd7a27
@@ -166,51 +166,6 @@
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.TimeBoxOrderTemplate>
<usp:OrderModificationTemplateSelector.TickOrderTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="1" VerticalAlignment="Center">Cross Thresh</TextBlock>
<uag:QuantityMeasureControl Grid.Row="1" Grid.Column="2" QuantityMeasure="{Binding cross_threshold}"/>
<TextBlock Grid.Row="3" VerticalAlignment="Center">Cross Ticks</TextBlock>
<c:TickUpDownUInt Grid.Row="3" Grid.Column="2" Value="{Binding cross_ticks}"/>
<TextBlock Grid.Row="5" VerticalAlignment="Center">Max Chase Ticks</TextBlock>
<c:TickUpDownUInt Grid.Row="5" Grid.Column="2" Value="{Binding max_chase_ticks}"/>
<CheckBox Grid.Row="7" Grid.Column="2" VerticalAlignment="Center" Margin="0,0,0,0" IsChecked="{Binding detach_on_toward}">Detach on Toward</CheckBox>
<TextBlock Grid.Row="9" VerticalAlignment="Center">Initial Tick Offset</TextBlock>
<c:TickUpDownUInt Grid.Row="9" Grid.Column="2" Value="{Binding tick_offset_on_deploy}"/>
<TextBlock Grid.Row="11">Child</TextBlock>
<uag:OrderDetailsPopupControl
Grid.Row="11" Grid.Column="2"
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding child_order_types}"
SelectedItem="{Binding child_order}"
HasEditableProperties="{Binding child_order.has_editable_properties, FallbackValue=False}"
/>
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.TickOrderTemplate>
<usp:OrderModificationTemplateSelector.LeanOrderTemplate>
<DataTemplate>
<Grid>
@@ -379,16 +334,16 @@
Orientation="Horizontal"
Grid.Row="1"
>
<TextBlock VerticalAlignment="Center" >Hedge Ticks</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the number of ticks to offset the hedge." />
<TextBlock VerticalAlignment="Center" >Profit Ticks</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the number of ticks in your favor to offset the profit/hedge order." />
</StackPanel>
<c:TickUpDownInt Grid.Row="1" Grid.Column="2" Value="{Binding hedge_ticks}"/>
<StackPanel
Orientation="Horizontal"
Grid.Row="3"
>
<TextBlock VerticalAlignment="Center">Hedge</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of the hedge order to send for each fill of Child Order." />
<TextBlock VerticalAlignment="Center">Profit Order</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of the profit/hedge order to send for each fill of Child Order." />
</StackPanel>
<uag:OrderDetailsPopupControl
Grid.Row="3" Grid.Column="2"
@@ -415,6 +370,68 @@
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.CoverOrderTemplate>
<usp:OrderModificationTemplateSelector.OCOOrderTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="4" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="1" >
<TextBlock VerticalAlignment="Center" >Stop Ticks</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the number of ticks away from the main order to start the 'stop' order." />
</StackPanel>
<c:TickUpDownInt Grid.Row="1" Grid.Column="2" Value="{Binding other_ticks}"/>
<StackPanel Orientation="Horizontal" Grid.Row="3" >
<TextBlock VerticalAlignment="Center" >Stop Side</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="The Side of the 'stop' order" />
</StackPanel>
<ComboBox Grid.Row="3" Grid.Column="2" ItemsSource="{Binding other_side_types}" ItemTemplate="{StaticResource EnumDescriptionTemplate}" SelectedItem="{Binding other_side}"/>
<StackPanel
Orientation="Horizontal"
Grid.Row="5"
>
<TextBlock VerticalAlignment="Center">Stop Order</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of the 'stop' order to send." />
</StackPanel>
<uag:OrderDetailsPopupControl
Grid.Row="5" Grid.Column="2"
IsOpen="{Binding other_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding other_order_types}"
SelectedItem="{Binding other_order}"
HasEditableProperties="{Binding other_order.has_editable_properties, FallbackValue=False}"
/>
<StackPanel
Orientation="Horizontal"
Grid.Row="7"
>
<TextBlock VerticalAlignment="Center">Child</TextBlock>
<c:HelpButton Margin="4,0,0,0" ToolTip="This is the type of order to be placed when the algo is triggered." />
</StackPanel>
<uag:OrderDetailsPopupControl
Grid.Row="7" Grid.Column="2"
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding child_order_types}"
SelectedItem="{Binding child_order}"
HasEditableProperties="{Binding child_order.has_editable_properties, FallbackValue=False}"
/>
</Grid>
</DataTemplate>
</usp:OrderModificationTemplateSelector.OCOOrderTemplate>
<usp:OrderModificationTemplateSelector.OffsetOrderTemplate>
<DataTemplate>
<Grid>
@@ -773,9 +790,11 @@
</usp:DynamicOrderParamTemplateSelector>
</ItemsControl.ItemTemplateSelector>
</ItemsControl>
<TextBlock Grid.Row="3">Child</TextBlock>
<TextBlock Grid.Row="3"
Visibility="{Binding has_child, Converter={StaticResource BooleanToVisibilityConverter}}" >Child</TextBlock>
<uag:OrderDetailsPopupControl
Grid.Row="3" Grid.Column="2"
Grid.Row="3" Grid.Column="2"
Visibility="{Binding has_child, Converter={StaticResource BooleanToVisibilityConverter}}"
IsOpen="{Binding child_order.editable_properties_open, FallbackValue=False}"
ItemsSource="{Binding child_order_types}"
SelectedItem="{Binding child_order}"
@@ -25,7 +25,6 @@ namespace mbts.spark.utilities {
static readonly OrderMetadata _default_order_metadata = new OrderMetadata { KeyBinding = "", Color = BTSColors.Orders.spreader_order };
static readonly CustomOrderDefinition.CustomOneofCase[]
// The following standard types are not yet ready for production use:
// CustomOrderDefinition.CustomOneofCase.Tick,
// CustomOrderDefinition.CustomOneofCase.Dynamic,
_standard_types = new[] {
CustomOrderDefinition.CustomOneofCase.Market,
@@ -37,6 +36,7 @@ namespace mbts.spark.utilities {
CustomOrderDefinition.CustomOneofCase.Lean,
CustomOrderDefinition.CustomOneofCase.Join,
CustomOrderDefinition.CustomOneofCase.Cover,
CustomOrderDefinition.CustomOneofCase.Oco,
CustomOrderDefinition.CustomOneofCase.Offset,
CustomOrderDefinition.CustomOneofCase.Top,
CustomOrderDefinition.CustomOneofCase.Trigger,
@@ -228,6 +228,15 @@ namespace mbts.spark.utilities {
Child = custom_order(),
Hedge = custom_order(),
};
public OCOOrderDefinition oco_order() => new OCOOrderDefinition
{
Child = custom_order(),
Other = custom_order(),
};
public PricerOrderDefinition pricer_order() => new PricerOrderDefinition
{
Child = custom_order(),
};
public OffsetOrderDefinition offset_order() => new OffsetOrderDefinition
{
Child = custom_order(),
@@ -262,6 +271,8 @@ namespace mbts.spark.utilities {
case CustomOrderDefinition.CustomOneofCase.Join: rv.Join = join_order(); break;
case CustomOrderDefinition.CustomOneofCase.Top: rv.Top = top_order(); break;
case CustomOrderDefinition.CustomOneofCase.Cover: rv.Cover = cover_order(); break;
case CustomOrderDefinition.CustomOneofCase.Oco: rv.Oco = oco_order(); break;
case CustomOrderDefinition.CustomOneofCase.Pricer: rv.Pricer = pricer_order(); break;
case CustomOrderDefinition.CustomOneofCase.Offset: rv.Offset = offset_order(); break;
case CustomOrderDefinition.CustomOneofCase.Trigger: rv.Trigger = trigger_order(); break;
case CustomOrderDefinition.CustomOneofCase.Spreader: rv.Spreader = spreader_order(); break;
@@ -285,6 +296,8 @@ namespace mbts.spark.utilities {
case CustomOrderDefinition.CustomOneofCase.Join: return new OrderMetadata { KeyBinding = "J", Color = BTSColors.Orders.join_order };
case CustomOrderDefinition.CustomOneofCase.Top: return new OrderMetadata { KeyBinding = "D", Color = BTSColors.Orders.top_order };
case CustomOrderDefinition.CustomOneofCase.Cover: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.cover_order };
case CustomOrderDefinition.CustomOneofCase.Oco: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.oco_order };
case CustomOrderDefinition.CustomOneofCase.Pricer: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.pricer_order };
case CustomOrderDefinition.CustomOneofCase.Offset: return new OrderMetadata { KeyBinding = "O", Color = BTSColors.Orders.tick_order };
case CustomOrderDefinition.CustomOneofCase.Trigger: return new OrderMetadata { KeyBinding = "T", Color = BTSColors.Orders.trigger_order };
case CustomOrderDefinition.CustomOneofCase.Spreader: goto default;
@@ -306,6 +319,8 @@ namespace mbts.spark.utilities {
case OrderState.CustomOneofCase.Join: return new OrderMetadata { KeyBinding = "J", Color = BTSColors.Orders.join_order };
case OrderState.CustomOneofCase.Top: return new OrderMetadata { KeyBinding = "D", Color = BTSColors.Orders.top_order };
case OrderState.CustomOneofCase.Cover: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.cover_order };
case OrderState.CustomOneofCase.Oco: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.oco_order };
case OrderState.CustomOneofCase.Pricer: return new OrderMetadata { KeyBinding = "C", Color = BTSColors.Orders.pricer_order };
case OrderState.CustomOneofCase.Offset: return new OrderMetadata { KeyBinding = "O", Color = BTSColors.Orders.tick_order };
case OrderState.CustomOneofCase.Trigger: return new OrderMetadata { KeyBinding = "T", Color = BTSColors.Orders.trigger_order };
case OrderState.CustomOneofCase.Spreader: goto default;
@@ -345,6 +360,8 @@ namespace mbts.spark.utilities {
case nameof(JoinOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Join;
case nameof(TopOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Top;
case nameof(CoverOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Cover;
case nameof(OCOOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Oco;
case nameof(PricerOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Pricer;
case nameof(OffsetOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Offset;
case nameof(TriggerOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Trigger;
case nameof(DynamicOrderDefinition): return CustomOrderDefinition.CustomOneofCase.Dynamic;
+1 -1
View File
@@ -141,4 +141,4 @@ if (WIN32)
include(${CMAKE_SOURCE_DIR}/tools/vs_filters.cmake)
endif()
+17
View File
@@ -73,6 +73,8 @@ message CustomOrderDefinition
TriggerOrderDefinition trigger = 22;
CoverOrderDefinition cover = 23;
OffsetOrderDefinition offset = 24;
OCOOrderDefinition oco = 25;
PricerOrderDefinition pricer = 26;
DynamicOrderDefinition dynamic = 1000;
}
@@ -154,6 +156,17 @@ message OffsetOrderDefinition {
uint32 tick_offset_on_deploy = 1;
CustomOrderDefinition child = 6;
}
message OCOOrderDefinition {
CustomOrderDefinition other = 1;
int32 other_ticks = 2;
api.RelativeSide other_side = 4;
CustomOrderDefinition child = 3;
}
message PricerOrderDefinition {
int32 price_offset_ticks = 1;
double price_factor = 2;
CustomOrderDefinition child = 3;
}
message DynamicOrderDefinition {
string dynamic_order_type = 1;
map<string, DynamicOrderParam> order_params = 2;
@@ -203,6 +216,8 @@ message OrderState {
TriggerOrderState trigger = 21;
CoverOrderState cover = 22;
OffsetOrderState offset = 24;
OCOOrderState oco = 25;
PricerOrderState pricer = 26;
DynamicOrderState dynamic = 255; // do not use anything bigger than 255, or things will break
}
@@ -276,6 +291,8 @@ message TopOrderState {}
message TriggerOrderState {}
message CoverOrderState {}
message OffsetOrderState {}
message OCOOrderState {}
message PricerOrderState {}
message DynamicOrderState {}
enum OrderStatus {
+1
View File
@@ -35,6 +35,7 @@
#include <stdlib.h>
#include <vector>
using std::vector;
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/stubs/stringpiece.h>
+8
View File
@@ -66,6 +66,14 @@ enum Side {
SIDE_SELL = 50;
}
enum RelativeSide {
RELATIVESIDE_UNDEFINED = 0;
RELATIVESIDE_OPPOSITE = 1;
RELATIVESIDE_SAME = 2;
RELATIVESIDE_BUY = 49;
RELATIVESIDE_SELL = 50;
}
enum PutOrCall {
PUTORCALL_PUT = 0;
PUTORCALL_CALL = 1;
@@ -11,7 +11,7 @@ namespace orderman {
class ChildOrder {
public:
ChildOrder()
: _order(nullptr), _parent_order_services(nullptr), _active(false) {}
: _order(nullptr), _parent_order_services(nullptr), _child_order_services(nullptr), _active(false) {}
ChildOrder(Order &o, OrderServices &services)
: _order(&o), _parent_order_services(&services),
@@ -122,6 +122,12 @@ class OrderStateUpdateEvent : public mercury::Event<OrderStateUpdateEvent> {
case api::orderman::OrderState::kOffset:
result.mutable_offset();
break;
case api::orderman::OrderState::kOco:
result.mutable_oco();
break;
case api::orderman::OrderState::kPricer:
result.mutable_pricer();
break;
case api::orderman::OrderState::kDynamic:
result.mutable_dynamic();
break;
@@ -18,7 +18,8 @@
#include "lib/orderman/orders/book_algos/JoinOrder.h"
#include "lib/orderman/orders/book_algos/LeanOrder.h"
#include "lib/orderman/orders/book_algos/OffsetOrder.h"
#include "lib/orderman/orders/book_algos/TickOrder.h"
#include "lib/orderman/orders/book_algos/OCOOrder.h"
#include "lib/orderman/orders/book_algos/PricerOrder.h"
#include "lib/orderman/orders/book_algos/TopOrder.h"
#include "lib/orderman/orders/spreader_orders/SpreaderOrder.h"
@@ -148,7 +149,7 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
order_ptr.reset(new orderman::TimeBoxOrder());
break;
case CustomOrderDefinition::kTick:
order_ptr.reset(new orderman::TickOrder());
bts_assert(false);
break;
case CustomOrderDefinition::kLean:
order_ptr.reset(new orderman::LeanOrder());
@@ -167,7 +168,13 @@ Order &OrderFactory::allocate(OrderKey k, OrderKey pk,
break;
case CustomOrderDefinition::kOffset:
order_ptr.reset(new orderman::OffsetOrder());
break;
break;
case CustomOrderDefinition::kOco:
order_ptr.reset(new orderman::OCOOrder());
break;
case CustomOrderDefinition::kPricer:
order_ptr.reset(new orderman::PricerOrder());
break;
case CustomOrderDefinition::kDynamic: {
order_ptr = me->dynamic_order_registry.build(
def.custom_def().dynamic().dynamic_order_type());
+258 -148
View File
@@ -1,7 +1,7 @@
#include "BookAlgo.h"
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
#include "lib/utils/PBUtils.h"
#include "lib/utils/helper_macros.h"
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
#include <google/protobuf/timestamp.pb.h>
namespace bts {
@@ -9,113 +9,165 @@ namespace orderman {
using namespace api::orderman;
struct BookAlgo::PImpl {
PImpl()
: services(nullptr), fake_detached_child(false), supports_hedge(false),
has_activated_child(false) {}
OrderServices *services;
struct BookAlgo::PImpl
{
PImpl() : services(nullptr), is_detached(false),
supports_hedge(false), has_activated_child(false)
{
}
OrderServices* services;
api::orderman::OrderDefinition def;
api::orderman::OrderState state;
OrderBuilder child_builder;
ChildOrder child;
api::orderman::OrderState child_state;
bool fake_detached_child;
bool supports_hedge;
OrderBuilder hedge_builder;
std::vector<ChildOrder> hedges;
using HedgeStateMap =
boost::container::flat_map<OrderKey, api::orderman::OrderState>;
HedgeStateMap hedges_state;
ChildOrder child;
api::orderman::OrderState child_state;
bool is_detached;
bool supports_hedge;
OrderBuilder hedge_builder;
BookAlgo::HedgeMap hedges;
BookAlgo::HedgeStateMap hedges_state;
double tick_size;
bool has_activated_child;
};
BookAlgo::BookAlgo() : me(new PImpl()) {}
BookAlgo::BookAlgo() : me(new PImpl())
{
}
BookAlgo::~BookAlgo() {}
const api::orderman::OrderDefinition &BookAlgo::definition() const {
const api::orderman::OrderDefinition& BookAlgo::definition() const
{
return me->def;
}
const api::orderman::OrderState &BookAlgo::this_state() const {
const api::orderman::OrderState& BookAlgo::this_state() const
{
return me->state;
}
void BookAlgo::set_price(double p) { me->state.set_price(p); }
void BookAlgo::set_quantity(uint32_t s) { me->state.set_quantity(s); }
const api::orderman::OrderState &BookAlgo::child_state() const {
return me->child_state;
void BookAlgo::set_price(double p)
{
me->state.set_price(p);
}
void BookAlgo::set_quantity(uint32_t s)
{
me->state.set_quantity(s);
}
void BookAlgo::set_child_price(double p) { me->child_state.set_price(p); }
const api::orderman::OrderState& BookAlgo::child_state() const
{
return me->child_state;
}
void BookAlgo::set_child_price(double p)
{
me->child_state.set_price(p);
}
void BookAlgo::set_child_quantity(uint32_t s) {
void BookAlgo::set_child_quantity(uint32_t s)
{
me->child_state.set_quantity(s);
}
void BookAlgo::activate_child(Price p, Quantity q) {
// per Pedro, activating the child is not a synchronous calls, and he asserts
// that this is done only once
if (!me->has_activated_child) {
void BookAlgo::activate_child(Price p, Quantity q)
{
//per Pedro, activating the child is not a synchronous calls, and he asserts that this is done only once
if(!me->has_activated_child)
{
me->child.activate(p, q);
me->has_activated_child = true;
}
}
void BookAlgo::update_child(Price p, Quantity q)
{
me->child.update(p, q);
}
void BookAlgo::cancel_child()
{
me->child.cancel();
}
void BookAlgo::build_and_send_hedge(Price p, Quantity q)
{
auto hedge = me->hedge_builder.build();
auto key = hedge.key();
me->hedges[key] = std::move(hedge);
me->hedges[key].activate(p, q);
}
void BookAlgo::update_child(Price p, Quantity q) { me->child.update(p, q); }
void BookAlgo::cancel_child() { me->child.cancel(); }
void BookAlgo::build_and_send_hedge(Price p, Quantity q) {
auto hedge = me->hedge_builder.build();
me->hedges.push_back(std::move(hedge));
me->hedges.back().activate(p, q);
double BookAlgo::tick_size() const
{
return me->tick_size;
}
double BookAlgo::tick_size() const { return me->tick_size; }
BookAlgo::HedgeStateMap& BookAlgo::hedges_state()
{
return me->hedges_state;
}
void BookAlgo::on_init_new(const api::orderman::OrderDefinition &def,
const PreActivationOrderServices &services) {
BookAlgo::HedgeMap& BookAlgo::hedges()
{
return me->hedges;
}
bool BookAlgo::is_detached() const
{
return me->is_detached;
}
void BookAlgo::on_init_new(const api::orderman::OrderDefinition& def,
const PreActivationOrderServices &services)
{
me->services = nullptr;
me->def = def;
me->child_state.set_status(ORDER_STATUS_INACTIVE);
me->child_state.set_status(ORDER_STATUS_INACTIVE);
OrderDefinition child_def = def;
setup_child(def, services, me->child_state, &child_def);
me->child_builder = OrderBuilder(key(), child_def, services, 1);
OrderDefinition hedge_def = def;
OrderDefinition hedge_def = def;
me->supports_hedge = setup_hedge(def, services, &hedge_def);
if (me->supports_hedge)
me->hedge_builder = OrderBuilder(key(), hedge_def, services, 4);
const bts::api::Security *sec =
services.sec_db.resolve(SecurityKey(def.security_key()));
if (sec) {
if(me->supports_hedge)
me->hedge_builder = OrderBuilder(key(), hedge_def, services, 4);
const bts::api::Security* sec = services.sec_db.resolve(SecurityKey(def.security_key()));
if(sec)
{
me->tick_size = sec->contract_spec().low_tick();
transition(ORDER_STATUS_INACTIVE);
} else {
}
else
{
auto msg = fmt::format("Unknown security: {}", def.security_key());
me->state.set_last_msg(msg);
transition(ORDER_STATUS_REJECTED_BY_SPARK, msg);
transition(ORDER_STATUS_REJECTED_BY_SPARK, msg);
}
}
void BookAlgo::on_init_recovered(const api::orderman::OrderRecord &rec,
const PreActivationOrderServices &) {
void BookAlgo::on_init_recovered(const api::orderman::OrderRecord& rec,
const PreActivationOrderServices &)
{
auto const &def = rec.def();
me->def = def;
me->state = rec.state();
switch (me->state.status()) {
case ORDER_STATUS_WORKING: {
switch (me->state.status())
{
case ORDER_STATUS_WORKING:
{
auto msg = "System restarted with active BookAlgo";
me->state.set_last_msg(msg);
transition(ORDER_STATUS_ERROR, msg);
@@ -139,24 +191,24 @@ void BookAlgo::on_init_recovered(const api::orderman::OrderRecord &rec,
}
}
void BookAlgo::on_activate(Price p, Quantity q, OrderServices &services,
trace::CorID const &) {
void BookAlgo::on_activate(Price p, Quantity q, OrderServices& services, trace::CorID const&)
{
bts_assert(!me->services);
me->services = &services;
switch (this_state().status()) {
switch (this_state().status())
{
case ORDER_STATUS_INACTIVE:
me->child_builder.activate(services);
if (me->supports_hedge)
me->child_builder.activate(services);
if(me->supports_hedge)
me->hedge_builder.activate(services);
me->child = me->child_builder.build();
set_price(p.value());
set_quantity(q.value());
services.subscribe_to_child_updates(
[this](auto const &os) { this->on_child_order_update(os); });
services.subscribe_to_book(
SecurityKey(me->def.security_key()),
[this](auto const &b) { this->on_book_update(b); });
[this](auto const &os) { this->on_child_order_update(os); });
services.subscribe_to_book(SecurityKey(me->def.security_key()),
[this](auto const &b) { this->on_book_update(b); });
transition(ORDER_STATUS_WORKING);
break;
@@ -172,7 +224,7 @@ void BookAlgo::on_activate(Price p, Quantity q, OrderServices &services,
// state)
case ORDER_STATUS_WORKING:
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_DISCONNECTED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
@@ -181,11 +233,14 @@ void BookAlgo::on_activate(Price p, Quantity q, OrderServices &services,
report_state();
}
void BookAlgo::on_update(Price p, Quantity q, trace::CorID const &) {
void BookAlgo::on_update(Price p, Quantity q, trace::CorID const&)
{
LOG(OrderMan, Info, "Updating BookAlgo {}", key().value());
switch (this_state().status()) {
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (child_state().status()) {
switch (child_state().status())
{
case ORDER_STATUS_INACTIVE:
set_price(p.value());
set_quantity(q.value());
@@ -193,8 +248,8 @@ void BookAlgo::on_update(Price p, Quantity q, trace::CorID const &) {
case ORDER_STATUS_WORKING:
set_price(p.value());
set_quantity(q.value());
if (!me->fake_detached_child)
me->child.update(p, q);
if(!me->is_detached)
me->child.update(p,q);
break;
case ORDER_STATUS_PENDING_WORKING:
// we launched our child but we are not yet able
@@ -204,7 +259,7 @@ void BookAlgo::on_update(Price p, Quantity q, trace::CorID const &) {
// if the child was in any of these states we couldn't be
// in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
@@ -235,22 +290,25 @@ void BookAlgo::on_update(Price p, Quantity q, trace::CorID const &) {
report_state();
}
void BookAlgo::on_crack(trace::CorID const &) {}
void BookAlgo::on_crack(trace::CorID const&) {}
void BookAlgo::on_cancel(trace::CorID const &) {
void BookAlgo::on_cancel(trace::CorID const&)
{
LOG(OrderMan, Info, "Canceling BookAlgo Order {}", key().value());
switch (this_state().status()) {
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (child_state().status()) {
switch (child_state().status())
{
case ORDER_STATUS_INACTIVE:
transition(ORDER_STATUS_CANCELED);
break;
case ORDER_STATUS_WORKING:
if (!me->fake_detached_child)
if(!me->is_detached)
me->child.cancel();
for (auto &i : me->hedges)
i.crack();
for(auto& i : me->hedges)
i.second.crack();
transition(ORDER_STATUS_CANCELED);
break;
case ORDER_STATUS_PENDING_WORKING:
@@ -259,7 +317,7 @@ void BookAlgo::on_cancel(trace::CorID const &) {
break;
// child cannot be in any of these if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
@@ -289,50 +347,103 @@ void BookAlgo::on_cancel(trace::CorID const &) {
report_state();
}
void BookAlgo::transition(api::orderman::OrderStatus new_status,
std::string msg) {
void BookAlgo::transition(api::orderman::OrderStatus new_status, std::string msg)
{
auto const &from = OrderStatus_Name(me->state.status());
auto const &to = OrderStatus_Name(new_status);
LOG(OrderMan, Info, "Transitioning BookAlgo {} from {} to {}. Msg: {}",
key().value(), from, to, msg);
LOG(OrderMan, Info, "Transitioning BookAlgo {} from {} to {}. Msg: {}", key().value(), from, to, msg);
me->state.set_status(new_status);
}
void BookAlgo::on_child_order_update(const OrderStateUpdateEvent &ev) {
if (me->fake_detached_child)
return;
if (ev.key != me->child.key())
void BookAlgo::on_child_order_update(const OrderStateUpdateEvent& ev)
{
if(me->is_detached)
return;
if(ev.key != me->child.key()) //hedge state change
{
api::orderman::OrderState orig_state = api::orderman::OrderState::default_instance(); //TODO this isn't quite right, should be hedgetype state
auto it = me->hedges_state.find(ev.key);
if(it != me->hedges_state.end())
orig_state = it->second;
me->hedges_state[ev.key] = ev.rebuild_state();
else {
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (ev.status)
{
case ORDER_STATUS_PENDING_WORKING:
break;
case ORDER_STATUS_WORKING:
process_hedge_state_change(orig_state, ev);
break;
case ORDER_STATUS_COMPLETED:
process_hedge_state_change(orig_state, ev);
transition(ORDER_STATUS_COMPLETED);
break;
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
process_hedge_state_change(orig_state, ev);
transition(ORDER_STATUS_ERROR, "Unexpected child order state");
break;
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
break;
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_COMPLETED:
break;
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
}
else //child state change
{
api::orderman::OrderState orig_state = child_state();
me->child_state = ev.rebuild_state();
switch (this_state().status()) {
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (ev.status) {
case ORDER_STATUS_PENDING_WORKING:
break;
case ORDER_STATUS_WORKING:
if (me->supports_hedge)
send_hedge_if_new_fills(orig_state, ev);
break;
case ORDER_STATUS_COMPLETED:
transition(ORDER_STATUS_COMPLETED);
if (me->supports_hedge)
send_hedge_if_new_fills(orig_state, ev);
break;
switch (ev.status)
{
case ORDER_STATUS_PENDING_WORKING:
break;
case ORDER_STATUS_WORKING:
process_child_state_change(orig_state, ev);
break;
case ORDER_STATUS_COMPLETED:
process_child_state_change(orig_state, ev);
transition(ORDER_STATUS_COMPLETED);
break;
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
transition(ORDER_STATUS_ERROR, "Unexpected child order state");
break;
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
process_child_state_change(orig_state, ev);
transition(ORDER_STATUS_ERROR, "Unexpected child order state");
break;
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
break;
@@ -354,56 +465,55 @@ void BookAlgo::on_child_order_update(const OrderStateUpdateEvent &ev) {
report_state();
}
void BookAlgo::report_state() {
auto merged_state = me->state;
void BookAlgo::report_state()
{
OrderState merged_state = me->state;
merged_state.set_filled_quantity(child_state().filled_quantity());
merged_state.set_last_price(child_state().last_price());
merged_state.set_avg_price(child_state().avg_price());
merged_state.set_display_status(
bts::api::orderman::OrderState_DisplayStatus::
OrderState_DisplayStatus_HIDDEN);
merged_state.set_display_status(bts::api::orderman::OrderState_DisplayStatus::OrderState_DisplayStatus_HIDDEN);
me->services->report_state(merged_state);
}
void BookAlgo::payup(const md::PriceSize &opposite,
const bts::orderman::BookUpdateEvent &,
uint32_t cross_ticks) {
void BookAlgo::payup(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks)
{
double new_price = opposite.price() + me->tick_size * cross_ticks;
me->child.update(Price(new_price), Quantity(this_state().quantity()));
report_state();
}
void BookAlgo::paydown(const md::PriceSize &opposite,
const bts::orderman::BookUpdateEvent &,
uint32_t cross_ticks) {
void BookAlgo::paydown(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks)
{
double new_price = opposite.price() - me->tick_size * cross_ticks;
me->child.update(Price(new_price), Quantity(this_state().quantity()));
report_state();
}
void BookAlgo::detach(bts::api::orderman::OrderStatus status_after_detach) {
me->fake_detached_child = true;
void BookAlgo::detach(bts::api::orderman::OrderStatus status_after_detach)
{
me->is_detached = true;
me->child.crack();
transition(status_after_detach);
report_state();
}
void BookAlgo::on_book_update(const bts::orderman::BookUpdateEvent &) {}
void BookAlgo::on_book_update(const bts::orderman::BookUpdateEvent&) {}
bool BookAlgo::setup_hedge(const api::orderman::OrderDefinition &,
const PreActivationOrderServices &,
api::orderman::OrderDefinition *) {
return false;
bool BookAlgo::setup_hedge(const api::orderman::OrderDefinition&, const PreActivationOrderServices&, api::orderman::OrderDefinition*)
{
return false;
}
void BookAlgo::send_hedge_if_new_fills(
const api::orderman::OrderState &orig_state,
const OrderStateUpdateEvent &new_state) {
UNUSED(orig_state);
UNUSED(new_state);
// uint32_t qty = new_state.state.filled_quantity() -
// orig_state.filled_quantity(); UNUSED(qty);
void BookAlgo::process_child_state_change(const api::orderman::OrderState& orig_state, const OrderStateUpdateEvent& new_state)
{
UNUSED(orig_state);UNUSED(new_state);
}
void BookAlgo::process_hedge_state_change(const api::orderman::OrderState& orig_state, const OrderStateUpdateEvent& new_state)
{
UNUSED(orig_state);UNUSED(new_state);
}
}
}
} // namespace orderman
} // namespace bts
@@ -34,7 +34,8 @@ protected:
api::orderman::OrderState&, api::orderman::OrderDefinition*) = 0;
virtual bool setup_hedge(const api::orderman::OrderDefinition& parent, const PreActivationOrderServices&,
api::orderman::OrderDefinition*);
virtual void send_hedge_if_new_fills(const api::orderman::OrderState&, const OrderStateUpdateEvent&);
virtual void process_child_state_change(const api::orderman::OrderState&, const OrderStateUpdateEvent&);
virtual void process_hedge_state_change(const api::orderman::OrderState&, const OrderStateUpdateEvent&);
virtual void on_child_order_update(const OrderStateUpdateEvent&);
virtual void on_book_update(const bts::orderman::BookUpdateEvent&);
@@ -50,6 +51,7 @@ private:
std::unique_ptr<PImpl> me;
protected:
double tick_size() const;
const api::orderman::OrderState& this_state() const;
void set_price(double);
void set_quantity(uint32_t);
@@ -60,9 +62,14 @@ protected:
void activate_child(Price p, Quantity q);
void update_child(Price, Quantity);
void cancel_child();
bool is_detached() const;
void build_and_send_hedge(Price, Quantity);
double tick_size() const;
typedef boost::container::flat_map<OrderKey, ChildOrder> HedgeMap;
typedef boost::container::flat_map<OrderKey, api::orderman::OrderState> HedgeStateMap;
HedgeStateMap& hedges_state();
HedgeMap& hedges();
};
}}
@@ -10,87 +10,94 @@ namespace orderman {
using namespace api::orderman;
struct CoverOrder::PImpl {
struct CoverOrder::PImpl
{
PImpl() {}
int hedge_ticks;
OrderDefinition hedge_def;
int hedge_ticks;
OrderDefinition hedge_def;
};
CoverOrder::CoverOrder() : me(new PImpl()) {}
CoverOrder::~CoverOrder() {}
void CoverOrder::setup_child(const api::orderman::OrderDefinition &this_def,
const PreActivationOrderServices &,
api::orderman::OrderState &initial_state,
api::orderman::OrderDefinition *out_child) {
void CoverOrder::setup_child(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderState& initial_state, api::orderman::OrderDefinition* out_child)
{
initial_state.mutable_cover();
auto const &cover_def = this_def.custom_def().cover();
auto const &cover_def = this_def.custom_def().cover();
*out_child->mutable_custom_def() = cover_def.child();
me->hedge_ticks = cover_def.hedge_ticks();
me->hedge_ticks = cover_def.hedge_ticks();
}
bool CoverOrder::setup_hedge(const api::orderman::OrderDefinition &this_def,
const PreActivationOrderServices &,
api::orderman::OrderDefinition *out_hedge) {
bool CoverOrder::setup_hedge(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderDefinition* out_hedge)
{
auto const &cover_def = this_def.custom_def().cover();
if (cover_def.has_hedge()) {
*out_hedge->mutable_custom_def() = cover_def.hedge();
if (definition().side() == api::SIDE_BUY)
if(cover_def.has_hedge())
{
*out_hedge->mutable_custom_def() = cover_def.hedge();
if(definition().side() == api::SIDE_BUY)
out_hedge->set_side(api::SIDE_SELL);
else
out_hedge->set_side(api::SIDE_BUY);
return true;
} else
}
else
return false;
}
void CoverOrder::send_hedge_if_new_fills(
const api::orderman::OrderState &orig_state,
const OrderStateUpdateEvent &new_state) {
void CoverOrder::process_child_state_change(const api::orderman::OrderState& orig_state, const OrderStateUpdateEvent& new_state)
{
uint32_t qty = new_state.filled_quantity - orig_state.filled_quantity();
if (qty > 0) {
if(qty > 0)
{
double prx = new_state.last_price;
if (definition().side() ==
api::SIDE_BUY) // if this is a buy, I'm going to sell my hedge, nticks
// higher than the fill price
if(definition().side() == api::SIDE_BUY) //if this is a buy, I'm going to sell my hedge, nticks higher than the fill price
prx = prx + tick_size() * me->hedge_ticks;
else
prx = prx - tick_size() * me->hedge_ticks;
build_and_send_hedge(Price(prx), Quantity(qty));
}
}
void CoverOrder::on_book_update(const bts::orderman::BookUpdateEvent &) {
switch (this_state().status()) {
void CoverOrder::on_book_update(const bts::orderman::BookUpdateEvent& )
{
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (child_state().status()) {
case ORDER_STATUS_INACTIVE: {
activate_child(Price(this_state().price()),
Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
report_state();
} break;
case ORDER_STATUS_WORKING: {
} break;
case ORDER_STATUS_PENDING_WORKING:
switch (child_state().status())
{
case ORDER_STATUS_INACTIVE:
{
activate_child(Price(this_state().price()), Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
report_state();
}
break;
// child cannot be in any of these states if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
case ORDER_STATUS_WORKING:
{
}
break;
}
case ORDER_STATUS_PENDING_WORKING:
break;
// child cannot be in any of these states if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
break;
case ORDER_STATUS_COMPLETED:
@@ -106,8 +113,9 @@ void CoverOrder::on_book_update(const bts::orderman::BookUpdateEvent &) {
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
}
}
}
}
} // namespace orderman
} // namespace bts
@@ -22,7 +22,7 @@ protected:
api::orderman::OrderState&, api::orderman::OrderDefinition*) override;
bool setup_hedge(const api::orderman::OrderDefinition& parent, const PreActivationOrderServices&,
api::orderman::OrderDefinition*) override;
void send_hedge_if_new_fills(const api::orderman::OrderState&, const OrderStateUpdateEvent&) override;
void process_child_state_change(const api::orderman::OrderState&, const OrderStateUpdateEvent&) override;
void on_book_update(const bts::orderman::BookUpdateEvent&) override;
private:
@@ -0,0 +1,256 @@
#include "OCOOrder.h"
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h"
#include "lib/utils/PBUtils.h"
#include "lib/utils/helper_macros.h"
#include <google/protobuf/timestamp.pb.h>
namespace bts {
namespace orderman {
using namespace api::orderman;
struct OCOOrder::PImpl
{
PImpl() {}
int other_ticks;
bts::api::RelativeSide other_side;
OrderDefinition other_def;
bool hedge_sent;
};
OCOOrder::OCOOrder() : me(new PImpl()) {}
OCOOrder::~OCOOrder() {}
void OCOOrder::setup_child(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderState& initial_state, api::orderman::OrderDefinition* out_child)
{
initial_state.mutable_oco();
auto const &oco_def = this_def.custom_def().oco();
*out_child->mutable_custom_def() = oco_def.child();
me->other_ticks = oco_def.other_ticks();
me->other_side = oco_def.other_side();
me->hedge_sent = false;
}
//hedge here means 'other'
bool OCOOrder::setup_hedge(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderDefinition* out_hedge)
{
auto const &oco_def = this_def.custom_def().oco();
if(oco_def.has_other())
{
*out_hedge->mutable_custom_def() = oco_def.other();
bts_assert_msg(me->other_side != api::RELATIVESIDE_UNDEFINED, "undefined relativeside");
if(oco_def.other_side() == api::RELATIVESIDE_BUY)
out_hedge->set_side(api::SIDE_BUY);
else if(oco_def.other_side() == api::RELATIVESIDE_SELL)
out_hedge->set_side(api::SIDE_SELL);
else if(oco_def.other_side() == api::RELATIVESIDE_SAME)
out_hedge->set_side(definition().side());
else if(oco_def.other_side() == api::RELATIVESIDE_OPPOSITE)
{
if(definition().side() == api::SIDE_BUY)
out_hedge->set_side(api::SIDE_SELL);
else
out_hedge->set_side(api::SIDE_BUY);
}
else
bts_assert_msg(false, "unknown relativeside");
return true;
}
else
return false;
}
void OCOOrder::process_child_state_change(const api::orderman::OrderState& orig_state, const OrderStateUpdateEvent& new_state)
{
uint32_t fill_qty = new_state.filled_quantity - orig_state.filled_quantity();
const auto& the_state = hedges_state();
auto& the_hedges = hedges();
for(const auto& i : the_state)
{
const auto& hedge_state = i.second;
uint32_t working_qty = hedge_state.quantity() - hedge_state.filled_quantity();
uint32_t newqty = working_qty - std::min(fill_qty, working_qty);
bts_assert(newqty <= working_qty);
auto it = the_hedges.find(i.first);
if(it != the_hedges.end())
{
if(newqty != working_qty)
{
if(newqty > 0)
{
LOG(OrderMan, Info, "OCO reducing hedge qty from {} to {}", working_qty, newqty);
it->second.update(Price(hedge_state.price()), Quantity(newqty));
}
else
it->second.cancel();
}
else if(new_state.status != api::orderman::OrderStatus::ORDER_STATUS_PENDING_WORKING &&
new_state.status != api::orderman::OrderStatus::ORDER_STATUS_WORKING)
{
it->second.cancel();
}
}
else
{
LOG(OrderMan, Error, "OCO Can't find hedge order {}", i.first);
cancel_child();
}
}
}
void OCOOrder::process_hedge_state_change(const api::orderman::OrderState& orig_state, const OrderStateUpdateEvent& new_state)
{
uint32_t fill_qty = new_state.filled_quantity - orig_state.filled_quantity();
uint32_t working_qty = child_state().quantity() - child_state().filled_quantity();
uint32_t newqty = working_qty - std::min(fill_qty, working_qty);
bts_assert(newqty <= working_qty);
if(newqty != working_qty)
{
if(newqty > 0)
{
LOG(OrderMan, Info, "OCO reducing child qty from {} to {}", working_qty, newqty);
update_child(Price(child_state().price()), Quantity(newqty));
}
else
cancel_child();
}
else if(new_state.status != api::orderman::OrderStatus::ORDER_STATUS_PENDING_WORKING &&
new_state.status != api::orderman::OrderStatus::ORDER_STATUS_WORKING)
{
cancel_child();
}
}
void OCOOrder::on_book_update(const bts::orderman::BookUpdateEvent& )
{
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (child_state().status())
{
case ORDER_STATUS_INACTIVE:
{
activate_child(Price(this_state().price()), Quantity(this_state().quantity()));
if(!me->hedge_sent)
{
double prx = this_state().price();
if(definition().side() == api::SIDE_BUY)
prx = prx + tick_size() * me->other_ticks;
else
prx = prx - tick_size() * me->other_ticks;
build_and_send_hedge( Price(prx), Quantity(this_state().quantity()) );
me->hedge_sent = true;
}
transition(ORDER_STATUS_WORKING);
report_state();
}
break;
case ORDER_STATUS_WORKING:
{
}
break;
case ORDER_STATUS_PENDING_WORKING:
break;
// child cannot be in any of these states if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
break;
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
break;
case ORDER_STATUS_INACTIVE:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_DISCONNECTED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
}
void OCOOrder::on_cancel(trace::CorID const&)
{
LOG(OrderMan, Info, "Canceling OCOOrder Order {}", key().value());
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (child_state().status())
{
case ORDER_STATUS_INACTIVE:
transition(ORDER_STATUS_CANCELED);
break;
case ORDER_STATUS_WORKING:
if(!is_detached())
{
cancel_child();
for(auto& i : hedges())
i.second.cancel();
}
transition(ORDER_STATUS_CANCELED);
break;
case ORDER_STATUS_PENDING_WORKING:
// child is running but it cannot be canceled at this point
transition(this_state().status(), "Cannot cancel order");
break;
// child cannot be in any of these if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
break;
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
transition(this_state().status(), "Cannot cancel order");
break;
// these are unreacheable for this order type
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
report_state();
}
}
}
@@ -0,0 +1,36 @@
#pragma once
#include "lib/orderman/orders/book_algos/BookAlgo.h"
namespace bts {
namespace orderman {
class OrderStateUpdateEvent;
class BookUpdateEvent;
//OCOOrder initializes the child order as normal
//it also initializes a 'hedge' or 'other' at the same time, the child and the hedge are managed with OCO semantics:
//when one fills the other's quantity is reduced (or cancelled on a full fill)
class OCOOrder : public BookAlgo
{
public:
OCOOrder();
virtual ~OCOOrder();
void on_cancel(trace::CorID const&) override ;
protected:
void setup_child(const api::orderman::OrderDefinition&, const PreActivationOrderServices&,
api::orderman::OrderState&, api::orderman::OrderDefinition*) override;
bool setup_hedge(const api::orderman::OrderDefinition& parent, const PreActivationOrderServices&,
api::orderman::OrderDefinition*) override;
void process_child_state_change(const api::orderman::OrderState&, const OrderStateUpdateEvent&) override;
void process_hedge_state_change(const api::orderman::OrderState&, const OrderStateUpdateEvent&) override;
void on_book_update(const bts::orderman::BookUpdateEvent&) override;
private:
struct PImpl;
std::unique_ptr<PImpl> me;
};
}}
@@ -10,65 +10,75 @@ namespace orderman {
using namespace api::orderman;
struct OffsetOrder::PImpl {
struct OffsetOrder::PImpl
{
PImpl() {}
uint32_t tick_offset_on_deploy;
uint32_t tick_offset_on_deploy;
};
OffsetOrder::OffsetOrder() : me(new PImpl()) {}
OffsetOrder::~OffsetOrder() {}
void OffsetOrder::setup_child(const api::orderman::OrderDefinition &this_def,
const PreActivationOrderServices &,
api::orderman::OrderState &initial_state,
api::orderman::OrderDefinition *out_child) {
initial_state.mutable_tick();
auto const &offset_def = this_def.custom_def().offset();
void OffsetOrder::setup_child(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderState& initial_state, api::orderman::OrderDefinition* out_child)
{
initial_state.mutable_offset();
auto const &offset_def = this_def.custom_def().offset();
*out_child->mutable_custom_def() = offset_def.child();
me->tick_offset_on_deploy = offset_def.tick_offset_on_deploy();
me->tick_offset_on_deploy = offset_def.tick_offset_on_deploy();
}
void OffsetOrder::on_book_update(const bts::orderman::BookUpdateEvent &book) {
switch (this_state().status()) {
void OffsetOrder::on_book_update(const bts::orderman::BookUpdateEvent& book)
{
switch (this_state().status())
{
case ORDER_STATUS_WORKING:
switch (child_state().status()) {
case ORDER_STATUS_INACTIVE: {
if (definition().side() == api::SIDE_BUY) {
const auto &same = book.book.side(api::Side::SIDE_BUY)[0];
double price =
same.price() - tick_size() * me->tick_offset_on_deploy;
activate_child(Price(price), Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
} else {
const auto &same = book.book.side(api::Side::SIDE_SELL)[0];
double price =
same.price() + tick_size() * me->tick_offset_on_deploy;
activate_child(Price(price), Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
switch (child_state().status())
{
case ORDER_STATUS_INACTIVE:
{
if(definition().side() == api::SIDE_BUY)
{
const auto& same = book.book.side(api::Side::SIDE_BUY)[0];
double price = same.price() - tick_size() * me->tick_offset_on_deploy;
activate_child(Price(price), Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
}
else
{
const auto& same = book.book.side(api::Side::SIDE_SELL)[0];
double price = same.price() + tick_size() * me->tick_offset_on_deploy;
activate_child(Price(price), Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
}
report_state();
}
report_state();
} break;
case ORDER_STATUS_WORKING: {
detach();
} break;
case ORDER_STATUS_PENDING_WORKING:
break;
// child cannot be in any of these states if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
case ORDER_STATUS_WORKING:
{
detach();
}
break;
}
case ORDER_STATUS_PENDING_WORKING:
break;
// child cannot be in any of these states if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
break;
case ORDER_STATUS_COMPLETED:
@@ -84,8 +94,9 @@ void OffsetOrder::on_book_update(const bts::orderman::BookUpdateEvent &book) {
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
}
}
}
}
} // namespace orderman
} // namespace bts
@@ -0,0 +1,40 @@
#include "PricerOrder.h"
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h"
#include "lib/utils/PBUtils.h"
#include <google/protobuf/timestamp.pb.h>
namespace bts {
namespace orderman {
using namespace api::orderman;
struct PricerOrder::PImpl
{
PImpl() {}
int32_t price_offset_ticks;
double price_factor;
};
PricerOrder::PricerOrder() : me(new PImpl()) {}
PricerOrder::~PricerOrder() {}
void PricerOrder::setup_child(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderState& initial_state, api::orderman::OrderDefinition* out_child)
{
initial_state.mutable_pricer();
auto const &pricer_def = this_def.custom_def().pricer();
*out_child->mutable_custom_def() = pricer_def.child();
me->price_offset_ticks = pricer_def.price_offset_ticks();
me->price_factor = pricer_def.price_factor();
}
}
}
@@ -0,0 +1,28 @@
#pragma once
#include "lib/orderman/orders/book_algos/BookAlgo.h"
namespace bts {
namespace orderman {
class OrderStateUpdateEvent;
class BookUpdateEvent;
//PricerOrder matches the bid (for buy) or offer (for sell) price of it's target security times a factor plus a constant
class PricerOrder : public BookAlgo
{
public:
PricerOrder();
virtual ~PricerOrder();
protected:
void setup_child(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderState&, api::orderman::OrderDefinition*) override;
private:
struct PImpl;
std::unique_ptr<PImpl> me;
};
}}
@@ -1,172 +0,0 @@
#include "TickOrder.h"
#include "lib/orderman/actors/order_manager/OrderBuilder.h"
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h"
#include "lib/utils/PBUtils.h"
#include <google/protobuf/timestamp.pb.h>
namespace bts {
namespace orderman {
using namespace api::orderman;
struct TickOrder::PImpl {
PImpl() {}
uint32_t tick_offset_on_deploy;
spark::QuantityMeasure cross_threshold;
uint32_t cross_ticks;
uint32_t max_chase_ticks;
bool detach_on_toward;
md::PriceSize opposite_at_inception;
};
TickOrder::TickOrder() : me(new PImpl()) {}
TickOrder::~TickOrder() {}
void TickOrder::setup_child(const api::orderman::OrderDefinition &this_def,
const PreActivationOrderServices &,
api::orderman::OrderState &initial_state,
api::orderman::OrderDefinition *out_child) {
initial_state.mutable_tick();
auto const &tick_def = this_def.custom_def().tick();
*out_child->mutable_custom_def() = tick_def.child();
me->tick_offset_on_deploy = tick_def.tick_offset_on_deploy();
me->cross_threshold = tick_def.cross_threshold();
me->cross_ticks = tick_def.cross_ticks();
me->max_chase_ticks = tick_def.max_chase_ticks();
me->cross_threshold = tick_def.cross_threshold();
me->detach_on_toward = tick_def.detach_on_toward();
}
void TickOrder::payup(const md::PriceSize &opposite,
const bts::orderman::BookUpdateEvent &,
uint32_t cross_ticks) {
double new_price = opposite.price() + tick_size() * cross_ticks;
double limit =
me->opposite_at_inception.price() + tick_size() * me->max_chase_ticks;
if (new_price <= limit)
update_child(Price(new_price), Quantity(this_state().quantity()));
else {
update_child(Price(limit), Quantity(this_state().quantity()));
detach();
}
report_state();
}
void TickOrder::paydown(const md::PriceSize &opposite,
const bts::orderman::BookUpdateEvent &,
uint32_t cross_ticks) {
double new_price = opposite.price() - tick_size() * cross_ticks;
double limit =
me->opposite_at_inception.price() - tick_size() * me->max_chase_ticks;
if (new_price >= limit)
update_child(Price(new_price), Quantity(this_state().quantity()));
else {
update_child(Price(limit), Quantity(this_state().quantity()));
detach();
}
report_state();
}
void TickOrder::on_book_update(const bts::orderman::BookUpdateEvent &book) {
switch (this_state().status()) {
case ORDER_STATUS_WORKING:
switch (child_state().status()) {
case ORDER_STATUS_INACTIVE: {
if (definition().side() == api::SIDE_BUY) {
me->opposite_at_inception = book.book.side(api::Side::SIDE_SELL)[0];
if (me->tick_offset_on_deploy > 0) {
double price = me->opposite_at_inception.price() -
tick_size() * me->tick_offset_on_deploy;
activate_child(Price(price), Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
} else {
activate_child(Price(this_state().price()),
Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
}
} else {
me->opposite_at_inception = book.book.side(api::Side::SIDE_BUY)[0];
if (me->tick_offset_on_deploy > 0) {
double price = me->opposite_at_inception.price() +
tick_size() * me->tick_offset_on_deploy;
activate_child(Price(price), Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
} else {
activate_child(Price(this_state().price()),
Quantity(this_state().quantity()));
transition(ORDER_STATUS_WORKING);
}
}
report_state();
} break;
case ORDER_STATUS_WORKING: {
Quantity thresh = SpreaderUtils::_quantity_threshold(
me->cross_threshold, Quantity(this_state().quantity()));
if (definition().side() == api::SIDE_BUY) {
const auto &opposite = book.book.side(api::Side::SIDE_SELL)[0];
if (opposite.price() < me->opposite_at_inception.price()) {
if (me->detach_on_toward)
detach();
else
me->opposite_at_inception = opposite;
} else if (opposite.price() > me->opposite_at_inception.price())
payup(opposite, book, me->cross_ticks);
else {
if (opposite.size() <= thresh.value())
payup(opposite, book, me->cross_ticks);
}
} else {
const auto &opposite = book.book.side(api::Side::SIDE_BUY)[0];
if (opposite.price() > me->opposite_at_inception.price()) {
if (me->detach_on_toward)
detach();
else
me->opposite_at_inception = opposite;
} else if (opposite.price() < me->opposite_at_inception.price())
paydown(opposite, book, me->cross_ticks);
else {
if (opposite.size() <= thresh.value())
paydown(opposite, book, me->cross_ticks);
}
}
} break;
case ORDER_STATUS_PENDING_WORKING:
break;
// child cannot be in any of these states if we are in the working state
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
break;
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
break;
case ORDER_STATUS_INACTIVE:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_DISCONNECTED:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
}
} // namespace orderman
} // namespace bts
@@ -1,35 +0,0 @@
#pragma once
#include "lib/orderman/orders/book_algos/BookAlgo.h"
namespace bts {
namespace orderman {
class OrderStateUpdateEvent;
class BookUpdateEvent;
//TickOrder deploys N ticks away from the initial opposite inside market and watches for it to trade below a certain size.
//If that size goes below a threshold or the market moves away, TickOrder Pays up once.
//The process repeats until the algo has paid up a max of N ticks from the original opposite inside order.
//If the market moves toward, the algo either starts watching the new inside market and keeps going or detaches depending on a parameter
class TickOrder : public BookAlgo
{
public:
TickOrder();
virtual ~TickOrder();
protected:
void setup_child(const api::orderman::OrderDefinition& this_def, const PreActivationOrderServices&,
api::orderman::OrderState&, api::orderman::OrderDefinition*) override;
void on_book_update(const bts::orderman::BookUpdateEvent&) override;
private:
void payup(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks) override;
void paydown(const md::PriceSize& opposite, const bts::orderman::BookUpdateEvent&, uint32_t cross_ticks) override;
private:
struct PImpl;
std::unique_ptr<PImpl> me;
};
}}
+2
View File
@@ -32,6 +32,8 @@ void init_plugins(SparkServices &services) {
auto &f = *iter;
auto pl = f.path().string();
if(pl.find("tensorflow.so") != std::string::npos)
continue;
LOG(Plugin, Info, "Attempting to initialize plugin {}", pl);
try {
auto init_plugin = boost::dll::import<void(SparkServices &)>(
+4
View File
@@ -12,6 +12,10 @@ add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/sdk
${CMAKE_CURRENT_SOURCE_DIR}/examples/build_examples.sh
${CMAKE_CURRENT_SOURCE_DIR}/examples/md_publisher_example.cpp
${CMAKE_CURRENT_SOURCE_DIR}/examples/order_plugin_example.cpp
${CMAKE_CURRENT_SOURCE_DIR}/examples/ai_order_plugin_example.cpp
${CMAKE_CURRENT_SOURCE_DIR}/examples/tf_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tensorflow/tfapi.cpp
${CMAKE_CURRENT_SOURCE_DIR}/tensorflow/tfapi.h
server_layout)
add_custom_target(sdk_dir ALL DEPENDS ${CMAKE_BINARY_DIR}/sdk)
@@ -0,0 +1,393 @@
#include "../tensorflow/tfapi.h"
#include "spark/lib/logging/logging.h"
#include "spark/lib/orderman/orders/DynamicOrder.h"
#include "spark/lib/plugin/SparkServices.h"
#include "spark/lib/orderman/actors/order_manager/ChildOrder.h"
#include "spark/lib/orderman/actors/order_manager/OrderBuilder.h"
#include "spark/lib/orderman/orders/DynamicOrder.h"
#include "spark/lib/utils/PBUtils.h"
#include "lib/config/protos/system.pb.h"
#include "lib/config/config.h"
using namespace bts::api::orderman;
using namespace bts::orderman;
using std::vector;
namespace bts {
namespace order_example {
class AISampleOrder : public DynamicOrder {
public:
AISampleOrder();
~AISampleOrder();
OrderDefinition const &definition() const override;
void on_init_new(OrderDefinition const &,
const PreActivationOrderServices &) override;
void on_init_recovered(OrderRecord const &,
const PreActivationOrderServices &) override;
void on_activate(Price, Quantity, OrderServices &,
trace::CorID const&) override;
void on_update(Price, Quantity, trace::CorID const&) override;
void on_crack(trace::CorID const &) override;
void on_cancel(trace::CorID const &) override;
private:
void report_state();
void send_next_child_order();
void merge_states(OrderState const &iceberg_state,
OrderState const &child_state, OrderState *merged);
void on_child_order_update(OrderStateUpdateEvent const &);
void transition(OrderStatus new_state, std::string const &msg);
void transition(OrderStatus new_state);
struct ActiveChild;
struct PImpl;
std::unique_ptr<PImpl> me;
};
struct AISampleOrder::ActiveChild {
ActiveChild() {}
ChildOrder order;
api::orderman::OrderState state;
void clear() { state = api::orderman::OrderState(); }
};
struct AISampleOrder::PImpl {
PImpl() : services(nullptr), child() {}
OrderServices *services;
api::orderman::OrderDefinition def;
api::orderman::OrderState state;
OrderBuilder child_builder;
ActiveChild child;
Quantity show_quantity;
};
AISampleOrder::AISampleOrder() : me(new PImpl()) {}
AISampleOrder::~AISampleOrder() {}
api::orderman::OrderDefinition const &AISampleOrder::definition() const {
return me->def;
}
void AISampleOrder::on_init_new(
api::orderman::OrderDefinition const &def,
const PreActivationOrderServices &services) {
me->def = def;
me->state.mutable_dynamic();
auto const &iceberg_def = def.custom_def().dynamic();
me->show_quantity =
Quantity(iceberg_def.order_params().at("show_size").as_uint32());
auto child_def = def;
*child_def.mutable_custom_def() =
iceberg_def.order_params().at("child").as_order_def();
if (me->show_quantity.value() != 0) {
me->child_builder = OrderBuilder(
key(), child_def, services,
std::max((size_t)1, (size_t)(me->show_quantity).value() / 10));
transition(ORDER_STATUS_INACTIVE);
} else {
auto msg = fmt::format("Show quantity must be greater than 0");
me->state.set_last_msg(msg);
transition(ORDER_STATUS_REJECTED_BY_SPARK, msg);
}
}
void AISampleOrder::on_init_recovered(
api::orderman::OrderRecord const &rec, const PreActivationOrderServices &) {
auto const &def = rec.def();
me->def = def;
me->state = rec.state();
switch (me->state.status()) {
case ORDER_STATUS_WORKING:
case ORDER_STATUS_DISCONNECTED: {
auto msg = "System restarted with active iceberg order";
me->state.set_last_msg(msg);
transition(ORDER_STATUS_ERROR, msg);
break;
}
// terminal states
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
break;
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
}
void AISampleOrder::on_activate(Price p, Quantity q,
OrderServices &services,
trace::CorID const &) {
bts_assert(!me->services);
me->services = &services;
me->child_builder.activate(services);
switch (me->state.status()) {
case ORDER_STATUS_INACTIVE:
me->state.set_price(p.value());
me->state.set_quantity(q.value());
services.subscribe_to_child_updates(
[this](auto const &os) { this->on_child_order_update(os); });
transition(ORDER_STATUS_WORKING);
send_next_child_order();
break;
// these are not possible since the on_init_recovered code
// would have transitioned us to error already
case ORDER_STATUS_WORKING:
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_DISCONNECTED: {
bts_assert(false);
break;
}
// terminal states
case ORDER_STATUS_ERROR:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
break;
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
report_state();
}
void AISampleOrder::on_update(Price p, Quantity q, trace::CorID const &) {
switch (me->state.status()) {
case ORDER_STATUS_WORKING:
case ORDER_STATUS_PENDING_WORKING:
LOG(Plugin, Info,
"Updating DynamicIceberg order {} to price {} quantity {}",
key().value(), p.value(), q.value());
me->state.set_price(p.value());
me->state.set_quantity(q.value());
break;
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
transition(me->state.status(), "Cannot update order");
break;
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
report_state();
}
void AISampleOrder::on_crack(trace::CorID const &) {}
void AISampleOrder::on_cancel(trace::CorID const &) {
switch (me->state.status()) {
case ORDER_STATUS_WORKING:
LOG(Plugin, Info, "Canceling DynamicIceberg Order {}", key().value());
me->child.order.cancel();
transition(ORDER_STATUS_CANCELED);
break;
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_COMPLETED:
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
transition(me->state.status(), "Cannot cancel order");
break;
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
report_state();
}
void AISampleOrder::report_state() {
if (me->child.state.filled_quantity()) {
api::orderman::OrderState merged_state;
merge_states(me->state, me->child.state, &merged_state);
me->services->report_state(merged_state);
} else
me->services->report_state(me->state);
}
void AISampleOrder::merge_states(
api::orderman::OrderState const &iceberg_state,
api::orderman::OrderState const &child_state,
api::orderman::OrderState *merged) {
auto child_order_fills = child_state.filled_quantity();
auto child_order_avg_price = child_state.avg_price();
auto child_order_last_price = child_state.last_price();
auto iceberg_fills = iceberg_state.filled_quantity();
auto iceberg_avg_price = iceberg_state.avg_price();
*merged = iceberg_state;
merged->set_filled_quantity(child_order_fills + iceberg_fills);
merged->set_last_price(child_order_last_price);
merged->set_avg_price((child_order_fills * child_order_avg_price +
iceberg_fills * iceberg_avg_price) /
(child_order_fills + iceberg_fills));
}
void AISampleOrder::send_next_child_order() {
bts_assert(me->state.quantity() > me->state.filled_quantity());
auto remaining = me->state.quantity() - me->state.filled_quantity();
auto to_send = std::min(remaining, me->show_quantity.value());
me->child.order = me->child_builder.build();
LOG(Plugin, Info,
"DynamicIceberg order {} creating new child order {} with size "
"{} price {}. Filled {} so far out of {}",
key().value(), me->child.order.key().value(), to_send, me->state.price(),
me->state.filled_quantity(), me->state.quantity());
me->child.order.activate(Price(me->state.price()), Quantity(to_send));
}
void AISampleOrder::on_child_order_update(
OrderStateUpdateEvent const &ev) {
switch (me->state.status()) {
case ORDER_STATUS_WORKING:
if (ev.key == me->child.order.key()) {
me->child.state = ev.rebuild_state();
switch (me->child.state.status()) {
case ORDER_STATUS_WORKING:
case ORDER_STATUS_PENDING_WORKING:
// nothing to do but report new state
break;
case ORDER_STATUS_COMPLETED: {
api::orderman::OrderState merged_state;
merge_states(me->state, me->child.state, &merged_state);
me->state = merged_state;
me->child.clear();
if (me->state.quantity() > me->state.filled_quantity())
send_next_child_order();
else
transition(ORDER_STATUS_COMPLETED);
break;
}
case ORDER_STATUS_CANCELED:
LOG(Plugin, Info,
"Unexpected cancel of child {} in DynamicIceberg Order {}. "
"Canceling parent",
ev.key.value(), key().value());
transition(ORDER_STATUS_CANCELED);
break;
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_ERROR:
me->child.clear();
transition(ORDER_STATUS_ERROR, "Unexpected child order state");
break;
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
} else {
LOG(Plugin, Info,
"DynamicIceberg order {} received update for non active child "
"order{} . update state = {} ",
key().value(), me->child.order.key().value(),
utils::pb::to_string(ev.rebuild_state()));
}
break;
case ORDER_STATUS_CANCELED:
case ORDER_STATUS_ERROR:
case ORDER_STATUS_DISCONNECTED:
case ORDER_STATUS_COMPLETED:
break;
case ORDER_STATUS_PENDING_WORKING:
case ORDER_STATUS_REJECTED_BY_SPARK:
case ORDER_STATUS_INACTIVE:
case OrderStatus_INT_MIN_SENTINEL_DO_NOT_USE_:
case OrderStatus_INT_MAX_SENTINEL_DO_NOT_USE_:
bts_assert(false);
break;
}
report_state();
}
void AISampleOrder::transition(api::orderman::OrderStatus new_status,
std::string const &msg) {
auto const &from = OrderStatus_Name(me->state.status());
auto const &to = OrderStatus_Name(new_status);
LOG(Plugin, Info,
"Transitioning dynamic iceberg order {} from {} to {}. Msg: {}",
key().value(), from, to, msg);
me->state.set_last_msg(msg);
me->state.set_status(new_status);
}
void AISampleOrder::transition(api::orderman::OrderStatus new_status) {
auto const &from = OrderStatus_Name(me->state.status());
auto const &to = OrderStatus_Name(new_status);
LOG(OrderMan, Info, "Transitioning dynamic iceberg order {} from {} to {}",
key().value(), from, to);
me->state.set_status(new_status);
}
} // namespace order_example
} // namespace bts
DynamicOrderDescriptor get_order_desc()
{
DynamicOrderDescriptor desc;
// order type name
desc.set_dynamic_order_type("AISampleOrder");
// show size
auto param = desc.add_param_desc();
param->set_param_name("show_size");
param->mutable_param_type()->set_primitive(DYNAMIC_ORDER_PRIMITIVE_UINT);
// child order
param = desc.add_param_desc();
param->set_param_name("child");
param->mutable_param_type()->set_primitive(DYNAMIC_ORDER_PRIMITIVE_ORDER_DEF);
return desc;
}
extern "C" void init_spark_plugin(bts::SparkServices &serv) {
using namespace bts;
if (config::get<config::DeploymentType>().type() == "dev") {
serv.register_dynamic_order(get_order_desc(),
[]() { return std::make_unique<bts::order_example::AISampleOrder>(); });
LOG(Plugin,Info, "Initialized ai_order_plugin_example.so");
}
}
+43 -2
View File
@@ -11,7 +11,7 @@ g++ -isystem ../externals/include \
-l spark \
-llttng-ust \
-ldl
g++ -isystem ../externals/include \
-I ../include \
-I ../include/spark \
@@ -22,5 +22,46 @@ g++ -isystem ../externals/include \
-o order_plugin_example.so \
order_plugin_example.cpp \
-Wl,-rpath,.. \
-L ../lib \
-L ../lib \
-l spark
g++ -isystem ../externals/include \
-I ../include \
-I ../include/spark \
-I ../externals/include \
-std=c++1z \
-fPIC \
-g \
-shared \
-o ai_order_plugin_example.so \
ai_order_plugin_example.cpp \
../tensorflow/tfapi.cpp \
-Wl,-rpath,. \
-Wl,-rpath,.. \
-Wl,-rpath,../lib/ \
-Wl,-rpath,./plugins \
-L ../lib \
-l spark \
-L ../externals/lib \
-l tensorflow
g++ -isystem ../externals/include \
-I ../include \
-I ../include/spark \
-I ../externals/include \
-I ../externals/include/tensorflow/contrib/makefile/gen/proto \
-std=c++1z \
-o tf_test \
tf_test.cpp \
../tensorflow/tfapi.cpp \
-Wl,-rpath,. \
-Wl,-rpath,../lib \
-Wl,-rpath,../externals/lib \
-L ../lib \
-l spark \
-L ../externals/lib \
-l tensorflow \
-lpthread \
-llttng-ust \
-ldl
@@ -72,6 +72,7 @@ api::orderman::OrderDefinition const &DynamicIcebergOrder::definition() const {
void DynamicIcebergOrder::on_init_new(
api::orderman::OrderDefinition const &def,
const PreActivationOrderServices &services) {
me->def = def;
me->state.mutable_dynamic();
+31
View File
@@ -0,0 +1,31 @@
#include "../tensorflow/tfapi.h"
#include <iostream>
using namespace std;
using namespace tensorflow;
using namespace tensorflow::c;
int main()
{
// int argc = 0;
// tensorflow::port::InitMain("", &argc, nullptr);
// const char* ver = TF_Version();
// cout << ver;
std::cout << "pre";
TF_Session* session = nullptr;
TFStatus status = bts::ml::create_tf_session(session);
if (!status.ok()) {
cout << status.code << "\n";
return 1;
}
cout << "loading saved model" << "\n";
TFStatus status2 = bts::ml::load_tf_model("/home/bts/rnn_saved_model/", session);
cout << "loaded saved model" << "\n";
if (!status2.ok()) {
cout << status2.code << "\n" << status2.error;
return 1;
}
cout << "Session successfully created.\n";
}
+4 -1
View File
@@ -26,13 +26,16 @@ ln -sf $1/server $1/sdk/lib
mkdir $1/sdk/examples
cp $2/examples/* $1/sdk/examples
cp $2/doc/* $1/sdk/doc
mkdir $1/sdk/tensorflow
cp $2/tensorflow/* $1/sdk/tensorflow
cp $2/sdk_shell.sh $1/sdk/sdk_shell.sh
cp $2/update_github.sh $1/sdk/update_github.sh
cp $2/README.md $1/sdk/README.md
# ln -sf $1/sdk/lib/defaults $1/sdk/examples/defaults
chmod +x $1/sdk/examples/build_examples.sh
chmod +x $1/sdk/sdk_shell.sh
chmod +x $1/sdk/update_github.sh
(cd $1/sdk/examples && ./build_examples.sh && ./md_publisher_example >/dev/null)
+130
View File
@@ -0,0 +1,130 @@
#include "tfapi.h"
#include "lib/utils/helper_macros.h"
#include <vector>
#include <iostream>
//no c++ api yet
//https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/label_image/main.cc
namespace tensorflow
{
namespace c
{
TFStatus::TFStatus(TF_Status& stat)
{
std::string msg(TF_Message(&stat));
this->error = msg;
this->code = TF_GetCode(&stat);
}
bool TFStatus::ok() const
{
return (int)code == 0;
}
}}
using namespace tensorflow::c;
using std::string;
using std::vector;
namespace bts
{
namespace ml
{
const std::string input_default_tag = "input";
const std::string output_default_tag = "output";
const std::string serving_default_tag = "serve";
tensorflow::c::TFStatus create_tf_session(TF_Session*& session)
{
TF_Graph* graph = TF_NewGraph();
TF_SessionOptions* options = TF_NewSessionOptions();
TF_Status* status = TF_NewStatus();
session = TF_NewSession(graph, options, status);
TFStatus stat(*status);
TF_DeleteStatus(status);
return stat;
}
tensorflow::c::TFStatus load_tf_model(const std::string& export_dir, TF_Session*& session)
{
std::unordered_set<std::string> tags({serving_default_tag});
return load_tf_model(export_dir, tags, session);
}
tensorflow::c::TFStatus load_tf_model(const std::string& export_dir, const std::unordered_set<std::string>& tags,
TF_Session*& session)
{
vector<char*> ctags;
for(auto& t : tags)
ctags.push_back(const_cast<char*>(t.c_str()));
TF_SessionOptions* session_options = TF_NewSessionOptions();
TF_Buffer* run_options = nullptr;
TF_Buffer* meta_graph_def = TF_NewBuffer(); //TODO get the protos here
TF_Graph* graph = TF_NewGraph();
TF_Status* status = TF_NewStatus();
session = TF_LoadSessionFromSavedModel(session_options, run_options, export_dir.c_str(), &ctags[0], ctags.size(),
graph, meta_graph_def, status);
TFStatus stat(*status);
TF_DeleteSessionOptions(session_options);
TF_DeleteBuffer(run_options);
TF_DeleteBuffer(meta_graph_def);
TF_DeleteStatus(status);
return stat;
}
// tensorflow::c::TFStatus execute(TF_Session& session,
// const vector<std::pair<std::string, TF_Tensor> >& inputs,
// const vector<std::string>& output_tensor_names,
// const vector<std::string>& target_node_names,
// vector<tensorflow::Tensor>* outputs)
// {
// TF_Buffer* run_options = nullptr;
// TF_SessionRun(&session, run_options,
// session.
// tensorflow::RunMetadata* run_metadata = nullptr;
// tensorflow::RunOptions run_options;
// Status status = bundle.session->Run(run_options, inputs, output_tensor_names, target_node_names, outputs, run_metadata);
// return status;
// }
}
}
// tensorflow::Status load_tf_model(const std::string& export_dir, const std::unordered_set<string>& tags, SavedModelBundle* const bundle)
// {
// tensorflow::SessionOptions session_options; //defaults
// tensorflow::RunOptions run_options;
// UNUSED(export_dir);
// UNUSED(tags);
// UNUSED(bundle);
// Status status = LoadSavedModel(session_options, run_options, export_dir, tags, bundle);
// return status;
// //return tensorflow::Status();
// }
// tensorflow::Status load_tf_model(const string& export_dir, const std::unordered_set<string>& tags, std::unique_ptr<SavedModelBundle>* bundle)
// {
// SessionBundleConfig config;
// for(auto& i : tags)
// config.add_saved_model_tags(i);
// std::unique_ptr<SavedModelBundleFactory> factory;
// Status stat = SavedModelBundleFactory::Create(config, &factory);
// if(stat.ok())
// {
// stat = factory->CreateSavedModelBundle(export_dir, bundle);
// }
// return stat;
// }
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <string>
namespace tensorflow
{
namespace c
{
#include "tensorflow/c/c_api.h"
#undef LOG
struct TFStatus
{
TFStatus(TF_Status&);
bool ok() const;
std::string error;
TF_Code code;
};
}
}
#include <unordered_set>
namespace bts
{
namespace ml
{
extern const std::string input_default_tag;
extern const std::string output_default_tag;
extern const std::string serving_default_tag;
tensorflow::c::TFStatus create_tf_session(tensorflow::c::TF_Session*& session);
tensorflow::c::TFStatus load_tf_model(const std::string& export_dir, tensorflow::c::TF_Session*& session);
tensorflow::c::TFStatus load_tf_model(const std::string& export_dir, const std::unordered_set<std::string>& tags,
tensorflow::c::TF_Session*& session);
// tensorflow::c::TFStatus execute(const tensorflow::c::TF_Session& session,
// const std::vector<std::pair<std::string, tensorflow::c::TF_Tensor> >& inputs,
// const std::vector<std::string>& output_tensor_names,
// const std::vector<std::string>& target_node_names,
// std::vector<tensorflow::Tensor>* outputs);
}
}
+46
View File
@@ -0,0 +1,46 @@
- Set
ExchangeSim {value {merge_with_md:false}}
in your spark.conf
- Use the order ticket to put in a 10 lot 55 dollar bid
- Open up a ladder for SIM:CLZ9 and put in 10 lot offers at 55.10, 55.11, 55.12 and 1 lot bids at 54.99 and 54.98
- Select OCO order from the menu.
-Set Stop Side to Same, Stop Type and Child type to Limit
-Set Stop Ticks to -1
-Put in a 1 lot bid at 54.93, you should see another 1 lot bid go in one tick worse
-Move these orders independently (but don't get filled)
-Cancel one order, the other should cancel
-Check that an order goes in 1 tick better than where you click if you set the Stop Ticks to 1
-Now set Stop Side to Opposite and Stop ticks to 3, send a 5 lot bid at 55.02
-You should see a 5 lot buy go in at 55.02 and a 5 lot sell at 55.05.
-Move the bid up to 55.03, the offer should not move
-Move the offer up to 55.06, the bid should stay put
- Cancel either the bid or the offer, the other will cancel. Set it up again and cancel the other side.
-Keep Stop Side at Opposite and Stop ticks to 3, send a 5 lot bid at 55.03
-Switch to normal limit orders, send a 1 lot buy at 55.06. You should see a fill at 06 and the 5 lot bid at 03 should reduce to 4
-Still with limit orders, send a 2 lot sell at 55.03. You should see a fill at 04 and the 4 lot offer at 06 should reduce to 2
- (you might see the sell order have 1/2 in the badge. This means 1 fill / 2 total quantity, however I think this is a bug because we are working 2 still and that is correct)
-Finally send a 2 lot buy (limit) at 55.06, you should see both the sell side OCO fill and the buy side OCO cancel
-Flip this section around buy vs sell and make sure it does the same thing
Now compose a bracket order (extra credit if you make a template for it in the new guis)
Select Cover
Set Profit ticks to 1,
Profit Order = OCO
Child=Limit
For the OCO
Stop Ticks = 3
Stop Side = Same
Stop Order = Trigger
Child = Limit
Send in a buy of this order at 55.05
Fill a 1 lot of this order at 55.05 (by putting in a Limit 55.05 sell)
You should see a 1 lot sell order go in at 55.06 and a 1 lot sell trigger at 55.03
Cancel one of those orders and the other should go away
+3 -1
View File
@@ -1 +1,3 @@
@"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools\VsDevCmd.bat"
rem @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Tools\VsDevCmd.bat"
@"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvars64.bat"