Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66ad51280f | ||
|
|
029edd8a86 | ||
|
|
dfdcbab2a0 | ||
|
|
6d7c0702f0 | ||
|
|
86eaddea93 | ||
|
|
57f8f3ff58 | ||
|
|
775df2850d | ||
|
|
cb2b15f10b | ||
|
|
60362a4c95 | ||
|
|
c6d7a8f38c | ||
|
|
7931c62b46 | ||
|
|
58518451c8 |
No files matched your search
@@ -39,6 +39,7 @@ SPARKD__CONFIG_DIR=src/server/sparkd/configurations/dev
|
||||
# Defaults to a volume named "sparkd_<config_port>" (e.g., sparkd_8000).
|
||||
# SPARKD__DATA_DIR=/home/bts/sparkdata/data
|
||||
SPARKD__SOURCE_DIR=install/sparkd-release-gcc
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/ubuntu/8000/sparkdata/conf/
|
||||
SPARKD__CONFIG_PORT=8000
|
||||
SPARKD__QUICKBUS_PORT=8001
|
||||
SPARKD__SIM_FIX_PORT=8002
|
||||
|
||||
Vendored
+1
-1
@@ -326,4 +326,4 @@
|
||||
"description": "Test to run",
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,43 @@ services:
|
||||
resources:
|
||||
limits:
|
||||
memory: "${SPARKD__MEMORY:-4gb}"
|
||||
sparkd-symbols:
|
||||
volumes:
|
||||
- ${SPARKD__DATA_DIR:-sparkd_data}:/home/bts/sparkdata/data
|
||||
- ${SPARKD__RUNTIME_CONF_DIR:-sparkd_conf}:/home/bts/sparkdata/conf
|
||||
build:
|
||||
dockerfile: src/server/sparkd/Dockerfile
|
||||
args:
|
||||
- IMAGE=${SPARKD__IMAGE}
|
||||
- SOURCE_DIR=${SPARKD__SOURCE_DIR}
|
||||
- CONFIG_DIR=${SPARKD__CONFIG_DIR}
|
||||
shm_size: "${SPARKD__SHM_SIZE:-512mb}"
|
||||
command: >
|
||||
sh -c "
|
||||
echo bts | sudo -S chown -R bts:bts /home/bts/sparkdata/data
|
||||
if [ -e "/home/bts/sparkdata/data/logging.sparkd/log" ]; then
|
||||
mv "/home/bts/sparkdata/data/logging.sparkd/log" "/home/bts/sparkdata/data/logging.sparkd/log_$(date '+%Y%m%d-%H%M')"
|
||||
fi
|
||||
ls -alh /home/bts/sparkdata/conf/
|
||||
cat /home/bts/sparkdata/conf/.env.local
|
||||
if [ -e "/home/bts/sparkdata/conf/.env.local" ]; then
|
||||
echo 'Sourcing /home/bts/sparkdata/conf/.env.local'
|
||||
set -a
|
||||
. /home/bts/sparkdata/conf/.env.local
|
||||
set +a
|
||||
fi
|
||||
./sparkd run"
|
||||
env_file:
|
||||
- .env
|
||||
- ${SPARKD__CONFIG_DIR}/.env
|
||||
ports:
|
||||
- "${SPARKD__CONFIG_PORT}:${SPARKD__CONFIG_PORT}"
|
||||
- "${SPARKD__QUICKBUS_PORT}:${SPARKD__QUICKBUS_PORT}"
|
||||
- "${SPARKD__SIM_FIX_PORT}:${SPARKD__SIM_FIX_PORT}"
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: "${SPARKD__MEMORY:-4gb}"
|
||||
|
||||
sparkd-tail:
|
||||
image: bluetradingsystems/linux_dotnet7
|
||||
|
||||
@@ -626,6 +626,22 @@
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock
|
||||
Grid.Column="6"
|
||||
x:Name="PART_SpreaderType_Label"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{StaticResource Margin.LHeaderPanelItem}"
|
||||
Text="Type"
|
||||
/>
|
||||
<ComboBox
|
||||
x:Name="PART_SpreaderType_DropDown"
|
||||
Grid.Column="7"
|
||||
HorizontalAlignment="Stretch"
|
||||
Margin="{StaticResource Margin.LHeaderPanelItem}"
|
||||
ItemsSource="{TemplateBinding SpreaderTypeItemsSource}"
|
||||
ItemTemplate="{StaticResource EnumDescriptionTemplate}"
|
||||
SelectedItem="{Binding SpreaderType, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
/>
|
||||
<!-- <TextBlock
|
||||
Grid.Column="6"
|
||||
x:Name="PART_HedgePricing_Label"
|
||||
VerticalAlignment="Center"
|
||||
@@ -642,7 +658,7 @@
|
||||
ItemTemplate="{StaticResource EnumDescriptionTemplate}"
|
||||
SelectedItem="{Binding HedgePricing, RelativeSource={RelativeSource TemplatedParent}}"
|
||||
Visibility="Collapsed"
|
||||
/>
|
||||
/> -->
|
||||
</Grid>
|
||||
<c:DataGridEx
|
||||
x:Name="PART_DataGrid"
|
||||
|
||||
@@ -237,6 +237,29 @@ namespace mbts.ui.spark {
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SpreaderTypeItemsSource
|
||||
public static readonly DependencyProperty SpreaderTypeItemsSourceProperty =
|
||||
WPFHelper.create_dp<IEnumerable, ExecutionStrategyEditor>(
|
||||
nameof(SpreaderTypeItemsSource));
|
||||
|
||||
public IEnumerable SpreaderTypeItemsSource {
|
||||
get => GetValue(SpreaderTypeItemsSourceProperty) as IEnumerable;
|
||||
set => SetValue(SpreaderTypeItemsSourceProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SpreaderType
|
||||
public static readonly DependencyProperty SpreaderTypeProperty =
|
||||
WPFHelper.create_dp<object, ExecutionStrategyEditor>(
|
||||
nameof(SpreaderType),
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault);
|
||||
|
||||
public object SpreaderType {
|
||||
get => GetValue(SpreaderTypeProperty);
|
||||
set => SetValue(SpreaderTypeProperty, value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override void OnApplyTemplate() =>
|
||||
_connect_leg_tuples();
|
||||
|
||||
|
||||
@@ -117,6 +117,14 @@ namespace bts.shell {
|
||||
public static QuoteInsideMarketDistanceThrottle QuoteInsideMarketDistanceThrottle => new QuoteInsideMarketDistanceThrottle();
|
||||
#endregion
|
||||
|
||||
public static SniperQuoteParams SniperQuoteParams => new() {
|
||||
NTicks = 0
|
||||
};
|
||||
|
||||
public static ReverseHedgeQuoteParams ReverseHedgeQuoteParams => new() {
|
||||
NTicks = 0
|
||||
};
|
||||
|
||||
#region PreHedge
|
||||
public static PreHedgeParams PreHedgeParams => new PreHedgeParams {
|
||||
MaxPriceFromInsideMarket = PreHedgeMaxPriceFromInsideMarket,
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
ContractPickerVM="{Binding contract_picker_vm}"
|
||||
HedgePricing="{Binding hedge_pricing}"
|
||||
HedgePricingItemsSource="{Binding hedge_pricing_options}"
|
||||
SpreaderType="{Binding spreader_type}"
|
||||
SpreaderTypeItemsSource="{Binding spreader_type_options}"
|
||||
UseFractionalTicks="{Binding use_fractional_ticks}"
|
||||
IntegerTickSize="{Binding integer_tick_size}"
|
||||
/>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
using mbts.ui.spark;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace mbts.spark {
|
||||
partial class SyntheticEditorVM {
|
||||
class IsQuoteModel : RowModelBase<bool> {
|
||||
public override string display_name { get; } = "Enable Quoting";
|
||||
public override string help_text { get; } = "This parameter is in the form of a check box, where if the box is checked the leg will be quoted versus not checked, it will not be shown in the market. If it is not actively quoted in the market, the leg will still be used for calculation of the entire synthetic.";
|
||||
public override string man_page { get; } = string.Empty;
|
||||
|
||||
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.IsActiveQuoting;
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) =>
|
||||
leg_tup.leg_params.IsActiveQuoting = value;
|
||||
|
||||
public override bool has_errors(IReadOnlyCollection<LegSpreaderParamsTuple> leg_tups) =>
|
||||
!leg_tups.Any(lt => lt.leg_params.IsActiveQuoting);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using mbts.ui.spark;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace mbts.spark;
|
||||
|
||||
partial class SyntheticEditorVM {
|
||||
class QuoteEnabledModel : RowModelBase<bool> {
|
||||
public override string display_name => string.Empty;
|
||||
public override string help_text => string.Empty;
|
||||
public override string man_page => string.Empty;
|
||||
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.Quote };
|
||||
|
||||
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.IsActiveQuoting;
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) =>
|
||||
leg_tup.leg_params.IsActiveQuoting = value;
|
||||
|
||||
public override bool has_errors(IReadOnlyCollection<LegSpreaderParamsTuple> leg_tups) =>
|
||||
!leg_tups.Any(lt => lt.leg_params.IsActiveQuoting);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
using bts.shell;
|
||||
|
||||
using mbts.ui.spark;
|
||||
|
||||
namespace mbts.spark;
|
||||
|
||||
partial class SyntheticEditorVM {
|
||||
class ReverseHedgeEnabledModel : RowModelBase<bool> {
|
||||
readonly ReverseHedgeTicksModel _ticks_model;
|
||||
|
||||
public ReverseHedgeEnabledModel(ReverseHedgeTicksModel ticks_model) =>
|
||||
_ticks_model = ticks_model;
|
||||
|
||||
public override string display_name => string.Empty;
|
||||
public override string help_text => string.Empty;
|
||||
public override string man_page => string.Empty;
|
||||
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.ReverseHedge };
|
||||
|
||||
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.ReverseHedgeQuoteParams is not null;
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
|
||||
if (value) {
|
||||
if (leg_tup.leg_params.ReverseHedgeQuoteParams is null) {
|
||||
leg_tup.leg_params.ReverseHedgeQuoteParams = SyntheticDataHelper.Defaults.ReverseHedgeQuoteParams;
|
||||
_ticks_model.apply_value(leg_tup);
|
||||
}
|
||||
} else {
|
||||
leg_tup.leg_params.ReverseHedgeQuoteParams = null;
|
||||
}
|
||||
_ticks_model.set_enabled(leg_tup, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
using bts.spark;
|
||||
|
||||
using mbts.ui.spark;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mbts.spark;
|
||||
|
||||
partial class SyntheticEditorVM {
|
||||
internal class ReverseHedgeTicksModel : RowModelBase<int> {
|
||||
readonly Dictionary<int, int> _value_store = new();
|
||||
|
||||
public override string display_name => "Ticks";
|
||||
public override string help_text => string.Empty;
|
||||
public override string man_page => string.Empty;
|
||||
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.ReverseHedge };
|
||||
|
||||
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_params(leg_tup).NTicks = _value_from_store(leg_tup);
|
||||
|
||||
public override int get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_params(leg_tup)?.NTicks ?? _value_from_store(leg_tup);
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, int value) {
|
||||
_value_store[leg_tup.id] = value;
|
||||
var s = _get_params(leg_tup);
|
||||
if (s is not null) {
|
||||
s.NTicks = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_params(leg_tup) != null;
|
||||
|
||||
ReverseHedgeQuoteParams _get_params(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.ReverseHedgeQuoteParams;
|
||||
|
||||
int _value_from_store(LegSpreaderParamsTuple leg_tup) =>
|
||||
_value_store.get_value(leg_tup.id, _ => 0);
|
||||
}
|
||||
}
|
||||
@@ -94,7 +94,9 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
private static class Sections {
|
||||
public static ParameterSection Quote => new ParameterSection("Quote");
|
||||
public static ParameterSection Sniper => new("Sniper", true);
|
||||
public static ParameterSection ReverseHedge => new("Reverse Hedge", true);
|
||||
public static ParameterSection Quote => new("Quote", true);
|
||||
public static ParameterSection PreHedge => new ParameterSection("Pre-Hedge");
|
||||
public static ParameterSection PostHedge => new ParameterSection("Post-Hedge");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using bts.shell;
|
||||
|
||||
using mbts.ui.spark;
|
||||
|
||||
namespace mbts.spark;
|
||||
|
||||
partial class SyntheticEditorVM {
|
||||
class SniperEnabledModel : RowModelBase<bool> {
|
||||
readonly SniperTicksModel _ticks_model;
|
||||
|
||||
public SniperEnabledModel(SniperTicksModel ticks_model) =>
|
||||
_ticks_model = ticks_model;
|
||||
|
||||
public override string display_name => string.Empty;
|
||||
public override string help_text => string.Empty;
|
||||
public override string man_page => string.Empty;
|
||||
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.Sniper };
|
||||
|
||||
public override bool get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.SniperQuoteParams is not null;
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, bool value) {
|
||||
if (value) {
|
||||
if (leg_tup.leg_params.SniperQuoteParams is null) {
|
||||
leg_tup.leg_params.SniperQuoteParams = SyntheticDataHelper.Defaults.SniperQuoteParams;
|
||||
_ticks_model.apply_value(leg_tup);
|
||||
}
|
||||
} else {
|
||||
leg_tup.leg_params.SniperQuoteParams = null;
|
||||
}
|
||||
_ticks_model.set_enabled(leg_tup, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using bts.spark;
|
||||
|
||||
using mbts.ui.spark;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace mbts.spark;
|
||||
|
||||
partial class SyntheticEditorVM {
|
||||
internal class SniperTicksModel : RowModelBase<int> {
|
||||
readonly Dictionary<int, int> _value_store = new();
|
||||
|
||||
public override string display_name => "Ticks";
|
||||
public override string help_text => string.Empty;
|
||||
public override string man_page => string.Empty;
|
||||
|
||||
public override ParameterSection[] section_path { get; } = new[] { Sections.Sniper };
|
||||
|
||||
public void apply_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_params(leg_tup).NTicks = _value_from_store(leg_tup);
|
||||
|
||||
public override int get_value(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_params(leg_tup)?.NTicks ?? _value_from_store(leg_tup);
|
||||
|
||||
public override void set_value(LegSpreaderParamsTuple leg_tup, int value) {
|
||||
_value_store[leg_tup.id] = value;
|
||||
var s = _get_params(leg_tup);
|
||||
if (s is not null) {
|
||||
s.NTicks = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool _get_enabled(LegSpreaderParamsTuple leg_tup) =>
|
||||
_get_params(leg_tup) != null;
|
||||
|
||||
SniperQuoteParams _get_params(LegSpreaderParamsTuple leg_tup) =>
|
||||
leg_tup.leg_params.SniperQuoteParams;
|
||||
|
||||
int _value_from_store(LegSpreaderParamsTuple leg_tup) =>
|
||||
_value_store.get_value(leg_tup.id, _ => 0);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
using HedgePricing = bts.spark.ExecutionStrategy.Types.HedgePricing;
|
||||
using SpreaderType = bts.spark.ExecutionStrategy.Types.SpreaderType;
|
||||
|
||||
namespace mbts.spark {
|
||||
/// <summary>
|
||||
@@ -47,6 +48,7 @@ namespace mbts.spark {
|
||||
int _integer_tick_size = 1;
|
||||
ExecutionStrategyImmutable _strategy;
|
||||
HedgePricing _hedge_pricing;
|
||||
SpreaderType _spreader_type;
|
||||
|
||||
/// <summary>
|
||||
/// Inititalizes a new instance of SyntheticEditorVM class. This constructor may only be used for already-existing synthetic securities (id must be non-zero).
|
||||
@@ -198,6 +200,8 @@ namespace mbts.spark {
|
||||
} else {
|
||||
_can_add_leg = backing(nameof(can_add_leg), false);
|
||||
}
|
||||
var sniper_ticks_model = new SniperTicksModel();
|
||||
var reverse_hedge_ticks_model = new ReverseHedgeTicksModel();
|
||||
var show_quantity_quantity = new ShowQuantityQuantityModel();
|
||||
|
||||
var quote_throttle_outside_ticks = new QuoteThrottleOutsideTicksModel();
|
||||
@@ -225,15 +229,18 @@ namespace mbts.spark {
|
||||
|
||||
var post_hedge_opposite_market_based_cross_threshold = new PostHedgeOppositeMarketVolumeBasedCrossThresholdModel();
|
||||
var post_hedge_opposite_market_based_cross_cross_ticks = new PostHedgeOppositeMarketVolumeBasedCrossCrossTicksModel();
|
||||
var is_quote_model = new IsQuoteModel();
|
||||
rows = new IRowModel[] {
|
||||
_quantity_model,
|
||||
_price_mult_model,
|
||||
is_quote_model,
|
||||
//new EnableHedgeModel(), //TAHA_SPREADER
|
||||
new HedgeRatioModel(),
|
||||
new SniperEnabledModel(sniper_ticks_model),
|
||||
sniper_ticks_model,
|
||||
new ReverseHedgeEnabledModel(reverse_hedge_ticks_model),
|
||||
reverse_hedge_ticks_model,
|
||||
//new MinLeanQtyModel(), //TAHA_SPREADER
|
||||
//new QuoteHiddenModel(),
|
||||
new QuoteEnabledModel(),
|
||||
new QuoteQueueHolderModel(),
|
||||
new MarketDataTypeModel(),
|
||||
new ShowQuantityEnabledModel(show_quantity_quantity),
|
||||
@@ -337,6 +344,13 @@ namespace mbts.spark {
|
||||
public HedgePricing hedge_pricing { get => _hedge_pricing; set => Set(ref _hedge_pricing, value); }
|
||||
public IEnumerable<HedgePricing> hedge_pricing_options => EnumHelper.get_values<HedgePricing>();
|
||||
|
||||
// spreader type
|
||||
public SpreaderType spreader_type {
|
||||
get => _spreader_type;
|
||||
set => Set(ref _spreader_type, value);
|
||||
}
|
||||
public IEnumerable<SpreaderType> spreader_type_options => EnumHelper.get_values<SpreaderType>();
|
||||
|
||||
public ExecutionStrategyImmutable get_strategy() {
|
||||
var mutable_strategy = _strategy.CloneToMutable();
|
||||
mutable_strategy.LegParamsMap.Clear();
|
||||
@@ -352,6 +366,7 @@ namespace mbts.spark {
|
||||
_synthetic.Exchange = Venue.Bts;
|
||||
_strategy = strategy;
|
||||
hedge_pricing = strategy.HedgePricing;
|
||||
spreader_type = strategy.SpreaderType;
|
||||
leg_tuples.SetItems(_get_legs(_synthetic, strategy));
|
||||
if (synthetic.HasContractSpec) {
|
||||
/// assign the fields <see cref="_use_fractional_ticks"/> and <see cref="_integer_tick_size"/>,
|
||||
|
||||
@@ -41,6 +41,8 @@ namespace mbts.spark {
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
using SpreaderType = bts.spark.ExecutionStrategy.Types.SpreaderType;
|
||||
|
||||
class LadderVM : DisposableViewModelBase, IWillLetYouKnowWhenIDispose, IKeyListener {
|
||||
static readonly Brush _transparent_status_brush = BTSColors.UI.transparent;
|
||||
|
||||
@@ -103,6 +105,7 @@ namespace mbts.spark {
|
||||
ulong _misc_time = 0;
|
||||
ulong _last_trade_time = 0;
|
||||
ulong _last_bbo_time = 0;
|
||||
SpreaderType _spreader_type = SpreaderType.Requote;
|
||||
IReadOnlyDictionary<uint, OrderRecordTuple> _cache = DictionaryHelper.empty<uint, OrderRecordTuple>();
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata> _favorite_algo_metadata_map =
|
||||
ImmutableDictionary<AlgoKey, LadderFavoriteAlgoMetadata>.Empty;
|
||||
@@ -126,6 +129,9 @@ namespace mbts.spark {
|
||||
size_calculator.display_settings = model.security_md.quantity_display;
|
||||
_slot_price_vs_orders = new Dictionary<double, LadderOrderVM>(_equality);
|
||||
this.order_properties_vm = order_properties_vm;
|
||||
if (model.security.HasSynthetic) {
|
||||
spreader_type_choices.AddRange(EnumHelper.get_values<SpreaderType>());
|
||||
}
|
||||
_session_high = backing(nameof(session_high), double.NaN);
|
||||
_session_low = backing(nameof(session_low), double.NaN);
|
||||
_day_change = backing(nameof(day_change), double.NaN);
|
||||
@@ -578,6 +584,12 @@ namespace mbts.spark {
|
||||
public ObservableCollection<FairValueLineVM> fair_value_lines { get; } =
|
||||
new ObservableCollection<FairValueLineVM>();
|
||||
|
||||
public SpreaderType spreader_type {
|
||||
get => _spreader_type;
|
||||
set => Set(ref _spreader_type, value);
|
||||
}
|
||||
public ObservableCollection<SpreaderType> spreader_type_choices { get; } = new();
|
||||
|
||||
public uint orders_column_width {
|
||||
get => _orders_column_width.Value;
|
||||
set => _orders_column_width.set(value);
|
||||
@@ -757,15 +769,21 @@ namespace mbts.spark {
|
||||
}
|
||||
|
||||
var order = order_properties_vm.create(side);
|
||||
if (order.CustomDef is not null) {
|
||||
if (order.CustomDef.Stop is not null) {
|
||||
order.CustomDef.Stop.StopPrice = price;
|
||||
} else if (order.CustomDef.StopLimit is not null) {
|
||||
var def = order.CustomDef;
|
||||
if (def is not null) {
|
||||
if (def.Stop is not null) {
|
||||
def.Stop.StopPrice = price;
|
||||
} else if (def.StopLimit is not null) {
|
||||
// swap the prices here so that the level clicked
|
||||
// in the ladder is the StopPrice (trigger) and the Price
|
||||
// is what was specificed in the extra parameter box
|
||||
(price, order.CustomDef.StopLimit.StopPrice) =
|
||||
(order.CustomDef.StopLimit.StopPrice, price);
|
||||
(price, def.StopLimit.StopPrice) =
|
||||
(def.StopLimit.StopPrice, price);
|
||||
} else if (def.Spreader is not null) {
|
||||
var strategy = def.Spreader.ExecutionStrategy;
|
||||
if (strategy is not null) {
|
||||
strategy.SpreaderType = spreader_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -956,6 +956,13 @@
|
||||
</Style>
|
||||
</uag:OrderDetailsPopupControl.Resources>
|
||||
</uag:OrderDetailsPopupControl>
|
||||
|
||||
<ComboBox
|
||||
Margin="2"
|
||||
ItemsSource="{Binding spreader_type_choices}"
|
||||
SelectedItem="{Binding spreader_type}"
|
||||
Visibility="{Binding HasItems, Mode=OneWay, RelativeSource={RelativeSource Self}, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
/>
|
||||
|
||||
<!-- Position into Qty Button -->
|
||||
<Button
|
||||
|
||||
@@ -164,6 +164,8 @@ namespace bts.shell.pnl {
|
||||
new() {
|
||||
// sod
|
||||
sod_pnl = op(a.sod_pnl, b.sod_pnl),
|
||||
sod_realized_pnl = op(a.sod_realized_pnl, b.sod_realized_pnl),
|
||||
sod_unrealized_pnl = op(a.sod_unrealized_pnl, b.sod_unrealized_pnl),
|
||||
sod_long_pos = op(a.sod_long_pos, b.sod_long_pos),
|
||||
sod_short_pos = op(a.sod_short_pos, b.sod_short_pos),
|
||||
sod_delta = op(a.sod_delta, b.sod_delta),
|
||||
@@ -175,6 +177,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// day
|
||||
day_pnl = op(a.day_pnl, b.day_pnl),
|
||||
day_realized_pnl = op(a.day_realized_pnl, b.day_realized_pnl),
|
||||
day_unrealized_pnl = op(a.day_unrealized_pnl, b.day_unrealized_pnl),
|
||||
day_long_pos = op(a.day_long_pos, b.day_long_pos),
|
||||
day_short_pos = op(a.day_short_pos, b.day_short_pos),
|
||||
day_delta = op(a.day_delta, b.day_delta),
|
||||
|
||||
@@ -39,6 +39,9 @@ namespace bts.shell {
|
||||
class PNLWindow : SparkWindow<PNLSaveState>, ISharedWindow {
|
||||
public const string WINDOW_TYPE = "PNL";
|
||||
public const string WINDOW_TITLE = "P&L Summary";
|
||||
// Cpp overrides aren't respected in pnl calc. Hide the "Override Cpp"
|
||||
// menu item until we fix it.
|
||||
const bool CAN_OVERRIDE_CPP = false;
|
||||
|
||||
static int _window_id_counter = 0;
|
||||
|
||||
@@ -156,7 +159,7 @@ namespace bts.shell {
|
||||
},
|
||||
new SparkCommandCommand(
|
||||
"Override CPP...", Icons.CurrencyExchange, new Command(_override_cpp)) {
|
||||
show_in_context_menu = true,
|
||||
show_in_context_menu = CAN_OVERRIDE_CPP,
|
||||
show_in_toolbar = false
|
||||
},
|
||||
SparkCommands.window_settings_command(new DialogCommand(_mk_settings_win)),
|
||||
|
||||
@@ -225,16 +225,28 @@ namespace bts.shell.pnl {
|
||||
get {
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.SODPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.SODPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_realized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.SODRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_realized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.SODRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_unrealized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.SODUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_unrealized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.SODUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_net_pos)} > 0", _animation(foreground: BTSColors.MarketData.bid, column: Columns.SODNetPos));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_net_pos)} < 0", _animation(foreground: BTSColors.MarketData.ask, column: Columns.SODNetPos));
|
||||
// day
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.DayPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.DayPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_realized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.DayRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_realized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.DayRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_unrealized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.DayUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_unrealized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.DayUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_net_pos)} > 0", _animation(foreground: BTSColors.MarketData.bid, column: Columns.DayNetPos));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_net_pos)} < 0", _animation(foreground: BTSColors.MarketData.ask, column: Columns.DayNetPos));
|
||||
// total
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.TotalPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.TotalPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_realized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.TotalRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_realized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.TotalRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_unrealized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.TotalUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_unrealized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.TotalUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_net_pos)} > 0", _animation(foreground: BTSColors.MarketData.bid, column: Columns.TotalNetPos));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_net_pos)} < 0", _animation(foreground: BTSColors.MarketData.ask, column: Columns.TotalNetPos));
|
||||
// working
|
||||
@@ -247,16 +259,28 @@ namespace bts.shell.pnl {
|
||||
get {
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.SODPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.SODPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_realized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.SODRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_realized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.SODRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_unrealized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.SODUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_unrealized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.SODUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_net_pos)} > 0", _animation(foreground: BTSColors.MarketData.bid, column: Columns.SODNetPos));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.sod_net_pos)} < 0", _animation(foreground: BTSColors.MarketData.ask, column: Columns.SODNetPos));
|
||||
// day
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.DayPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.DayPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_realized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.DayRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_realized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.DayRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_unrealized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.DayUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_unrealized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.DayUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_net_pos)} > 0", _animation(foreground: BTSColors.MarketData.bid, column: Columns.DayNetPos));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.day_net_pos)} < 0", _animation(foreground: BTSColors.MarketData.ask, column: Columns.DayNetPos));
|
||||
// total
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.TotalPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.TotalPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_realized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.TotalRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_realized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.TotalRealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_unrealized_pnl)} > 0", _animation(foreground: BTSColors.PNL.profit, column: Columns.TotalUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_unrealized_pnl)} < 0", _animation(foreground: BTSColors.PNL.loss, column: Columns.TotalUnrealizedPNL));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_net_pos)} > 0", _animation(foreground: BTSColors.MarketData.bid, column: Columns.TotalNetPos));
|
||||
yield return _trigger($"{nameof(PNLNormalizedData.total_net_pos)} < 0", _animation(foreground: BTSColors.MarketData.ask, column: Columns.TotalNetPos));
|
||||
// working
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace bts.shell.pnl {
|
||||
_cell_map.set_appearances(default_appearances);
|
||||
// sod
|
||||
sod_pnl = _cell_map.add_pnl_decimal(ColumnKeys.SODPNL, d => d.sod_pnl);
|
||||
sod_realized_pnl = _cell_map.add_pnl_decimal(ColumnKeys.SODRealizedPNL, d => d.sod_realized_pnl);
|
||||
sod_unrealized_pnl = _cell_map.add_pnl_decimal(ColumnKeys.SODUnrealizedPNL, d => d.sod_unrealized_pnl);
|
||||
sod_net_pos = _cell_map.add_net_pos(ColumnKeys.SODNetPos, d => d.sod_net_pos);
|
||||
sod_long_pos = _cell_map.add_long_pos(ColumnKeys.SODLongPos, d => d.sod_long_pos);
|
||||
sod_short_pos = _cell_map.add_short_pos(ColumnKeys.SODShortPos, d => d.sod_short_pos);
|
||||
@@ -44,6 +46,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// day
|
||||
day_pnl = _cell_map.add_pnl(ColumnKeys.DayPNL, d => d.day_pnl);
|
||||
day_realized_pnl = _cell_map.add_pnl_decimal(ColumnKeys.DayRealizedPNL, d => d.day_realized_pnl);
|
||||
day_unrealized_pnl = _cell_map.add_pnl_decimal(ColumnKeys.DayUnrealizedPNL, d => d.day_unrealized_pnl);
|
||||
day_net_pos = _cell_map.add_net_pos(ColumnKeys.DayNetPos, d => d.day_net_pos);
|
||||
day_long_pos = _cell_map.add_long_pos(ColumnKeys.DayLongPos, d => d.day_long_pos);
|
||||
day_short_pos = _cell_map.add_short_pos(ColumnKeys.DayShortPos, d => d.day_short_pos);
|
||||
@@ -58,6 +62,8 @@ namespace bts.shell.pnl {
|
||||
working_short_pos = _cell_map.add_short_pos(ColumnKeys.WorkingShortPos, r => r.working_short_pos);
|
||||
// total
|
||||
total_pnl = _cell_map.add_pnl_decimal(ColumnKeys.TotalPNL, d => d.total_pnl);
|
||||
total_realized_pnl = _cell_map.add_pnl_decimal(ColumnKeys.TotalRealizedPNL, d => d.total_realized_pnl);
|
||||
total_unrealized_pnl = _cell_map.add_pnl_decimal(ColumnKeys.TotalUnrealizedPNL, d => d.total_unrealized_pnl);
|
||||
total_net_pos = _cell_map.add_net_pos(ColumnKeys.TotalNetPos, d => d.total_net_pos);
|
||||
total_long_pos = _cell_map.add_long_pos(ColumnKeys.TotalLongPos, d => d.total_long_pos);
|
||||
total_short_pos = _cell_map.add_short_pos(ColumnKeys.TotalShortPos, d => d.total_short_pos);
|
||||
@@ -88,6 +94,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// day
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_realized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_unrealized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_long_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_short_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_net_pos { get; }
|
||||
@@ -98,6 +106,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// sod
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_realized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_unrealized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_long_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_short_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_net_pos { get; }
|
||||
@@ -108,6 +118,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// total
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_realized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_unrealized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_net_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_long_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_short_pos { get; }
|
||||
|
||||
@@ -118,6 +118,8 @@ namespace bts.shell.pnl {
|
||||
});
|
||||
// sod
|
||||
sod_pnl = _cell_map.add_pnl(ColumnKeys.SODPNL, d => d.sod_pnl);
|
||||
sod_realized_pnl = _cell_map.add_pnl(ColumnKeys.SODRealizedPNL, d => d.sod_realized_pnl);
|
||||
sod_unrealized_pnl = _cell_map.add_pnl(ColumnKeys.SODUnrealizedPNL, d => d.sod_unrealized_pnl);
|
||||
sod_net_pos = _cell_map.add_net_pos(ColumnKeys.SODNetPos, d => d.display_sod_net_pos);
|
||||
sod_long_pos = _cell_map.add_long_pos(ColumnKeys.SODLongPos, d => d.display_sod_long_pos);
|
||||
sod_short_pos = _cell_map.add_short_pos(ColumnKeys.SODShortPos, d => d.display_sod_short_pos);
|
||||
@@ -128,6 +130,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// day
|
||||
day_pnl = _cell_map.add_pnl(ColumnKeys.DayPNL, d => d.day_pnl);
|
||||
day_realized_pnl = _cell_map.add_pnl(ColumnKeys.DayRealizedPNL, d => d.day_realized_pnl);
|
||||
day_unrealized_pnl = _cell_map.add_pnl(ColumnKeys.DayUnrealizedPNL, d => d.day_unrealized_pnl);
|
||||
day_net_pos = _cell_map.add_net_pos(ColumnKeys.DayNetPos, d => d.display_day_net_pos);
|
||||
day_long_pos = _cell_map.add_long_pos(ColumnKeys.DayLongPos, d => d.display_day_long_pos);
|
||||
day_short_pos = _cell_map.add_short_pos(ColumnKeys.DayShortPos, d => d.display_day_short_pos);
|
||||
@@ -138,6 +142,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// total
|
||||
total_pnl = _cell_map.add(ColumnKeys.TotalPNL, d => d.total_pnl, FormattingDelegates.Price<decimal>.Value);
|
||||
total_realized_pnl = _cell_map.add_pnl(ColumnKeys.TotalRealizedPNL, d => d.total_realized_pnl);
|
||||
total_unrealized_pnl = _cell_map.add_pnl(ColumnKeys.TotalUnrealizedPNL, d => d.total_unrealized_pnl);
|
||||
total_net_pos = _cell_map.add(ColumnKeys.TotalNetPos, d => d.display_total_net_pos);
|
||||
total_long_pos = _cell_map.add(ColumnKeys.TotalLongPos, d => d.display_total_long_pos);
|
||||
total_short_pos = _cell_map.add(ColumnKeys.TotalShortPos, d => d.display_total_short_pos);
|
||||
@@ -181,6 +187,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// sod
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_realized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_unrealized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_net_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_long_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> sod_short_pos { get; }
|
||||
@@ -191,6 +199,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// day
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_realized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_unrealized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_net_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_long_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> day_short_pos { get; }
|
||||
@@ -201,6 +211,8 @@ namespace bts.shell.pnl {
|
||||
|
||||
// total
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_realized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_unrealized_pnl { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_net_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_long_pos { get; }
|
||||
public PNLCellVM<PNLNormalizedData, decimal> total_short_pos { get; }
|
||||
|
||||
@@ -266,6 +266,7 @@
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="Margin" Value="4,0,0,0"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="Foreground" Value="{u:BTSColor UI.default_text}"/>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="HeaderRowCellText" TargetType="TextBlock">
|
||||
|
||||
Binary file not shown.
@@ -290,7 +290,8 @@ struct GeneralMarketDataListener::PImpl {
|
||||
// if this is set to true, then the security key passed on in the
|
||||
// on_securities function is used. If this is not set to true, then a new key
|
||||
// is generated
|
||||
const bool use_given_sec_key = false;
|
||||
const bool use_given_sec_key =
|
||||
true; // with true, replay works, with orders goign in ((did not push it in, since it was always false - need to test))
|
||||
const std::string cc_name_prefix = "cc_security";
|
||||
size_t n_bk_updates = 0;
|
||||
bts::persistence::IDGenerator &id_gen =
|
||||
|
||||
@@ -55,24 +55,24 @@ OkxExecutionGateway::~OkxExecutionGateway() {}
|
||||
enum class OkxExecutionState { OFF, STARTED, LOGGED_IN, SUBSCIRBED };
|
||||
void OkxExecutionGateway::send_msgs(
|
||||
std::vector<OrderMsg> const &msgs, trace::CorID) {
|
||||
LOG(OrderMan,Info,"ExecutionGateway::send_msgs" );
|
||||
LOG(OrderMan, Info, "ExecutionGateway::send_msgs");
|
||||
for (const auto &msg : msgs) {
|
||||
std::visit(
|
||||
[this](auto &&order) {
|
||||
using T = std::decay_t<decltype(order)>;
|
||||
if constexpr (std::is_same_v<T, CreateOrderMsg>) {
|
||||
LOG(OrderMan,Warn,"ExecutionGateway::CreateOrderMsg" );
|
||||
LOG(OrderMan, Warn, "ExecutionGateway::CreateOrderMsg");
|
||||
launch_new_order(order);
|
||||
|
||||
|
||||
} else if constexpr (std::is_same_v<T, CancelOrderMsg>) {
|
||||
LOG(OrderMan,Warn,"ExecutionGateway::CancelOrderMsg" );
|
||||
LOG(OrderMan, Warn, "ExecutionGateway::CancelOrderMsg");
|
||||
cancel_order(order);
|
||||
} else if constexpr (std::is_same_v<T, CancelReplaceOrderMsg>) {
|
||||
LOG(OrderMan,Warn,"ExecutionGateway::CancelReplaceOrderMsg" );
|
||||
LOG(OrderMan, Warn, "ExecutionGateway::CancelReplaceOrderMsg");
|
||||
modify_order(order);
|
||||
} else if constexpr (std::is_same_v<T, RFQMsg>) {
|
||||
// Handle RFQMsg if necessary
|
||||
// adapter->handle_rfq(order); // Example placeholder
|
||||
// Handle RFQMsg if necessary
|
||||
// adapter->handle_rfq(order); // Example placeholder
|
||||
}
|
||||
},
|
||||
msg);
|
||||
@@ -94,7 +94,8 @@ struct OkxExecutionGateway::PImpl {
|
||||
const std::string passphrase = config::get<config::OkxExeCfg>().passphrase();
|
||||
const std::string url =
|
||||
config::get<config::OkxExeCfg>().ws_url() + "/ws/v5/private";
|
||||
const bool simulated_trading = config::get<config::OkxExeCfg>().simulated_trading();
|
||||
const bool simulated_trading =
|
||||
config::get<config::OkxExeCfg>().simulated_trading();
|
||||
const std::string tdmode = config::get<config::OkxExeCfg>().tdmode();
|
||||
const core::TimeSpan connect_timeout = core::TimeSpan::from_seconds(0);
|
||||
const core::TimeSpan pong_timeout = core::TimeSpan::from_seconds(
|
||||
@@ -124,7 +125,8 @@ struct OkxExecutionGateway::PImpl {
|
||||
}
|
||||
}
|
||||
|
||||
static void dummy(std::shared_ptr<const ExecutionReport>, const trace::CorID &) {
|
||||
static void dummy(
|
||||
std::shared_ptr<const ExecutionReport>, const trace::CorID &) {
|
||||
LOG(OrderMan, Error, "OnixFixListener::Dummy fired");
|
||||
}
|
||||
void setCallback(const OnExeReport &callback) {
|
||||
@@ -185,7 +187,7 @@ struct OkxExecutionGateway::PImpl {
|
||||
Price(std::stod(order.at("lastPx").get<std::string>()));
|
||||
report.avg_price = Price(std::stod(order.at("avgPx").get<std::string>()));
|
||||
report.last_shares = Quantity::create_new(
|
||||
std::stod(order.at("fillSz").get<std::string>()));
|
||||
std::stod(order.at("fillSz").get<std::string>()));
|
||||
|
||||
//there are algos, like spreader
|
||||
// that are super sensitive to messages and cancel themselves. To avoid
|
||||
@@ -195,29 +197,28 @@ struct OkxExecutionGateway::PImpl {
|
||||
// Alternatively we can change the spreader to not do that. Right not this
|
||||
// seems to be the better choice
|
||||
if (!(order.at("code").get<std::string>() == "0")) {
|
||||
report.msg = order.at("msg").get<std::string>();
|
||||
}
|
||||
report.msg = order.at("msg").get<std::string>();
|
||||
}
|
||||
|
||||
//report can be new order, cancel order, order filled, replace order, and partial fill or errror
|
||||
//new order, cancelled and order filled dont need special handling, error gets handled above
|
||||
//for other three we will look for fields that are only specific to the respectives types
|
||||
// if (!(order.at("cancelSource").get<std::string>() == "")) {
|
||||
|
||||
//report can be new order, cancel order, order filled, replace order, and partial fill or errror
|
||||
//new order, cancelled and order filled dont need special handling, error gets handled above
|
||||
//for other three we will look for fields that are only specific to the respectives types
|
||||
// if (!(order.at("cancelSource").get<std::string>() == "")) {
|
||||
|
||||
// }
|
||||
// }
|
||||
if (!(order.at("amendSource").get<std::string>() == "")) {
|
||||
if((order.at("amendResult").get<std::string>() == "0"))
|
||||
if ((order.at("amendResult").get<std::string>() == "0"))
|
||||
report.exec_type = api::orderman::ExecType::EXEC_TYPE_REPLACED;
|
||||
else{
|
||||
else {
|
||||
LOG(OrderMan, Warn, "order:{} replace rejected", report.order_key);
|
||||
report.msg = order.at("msg").get<std::string>();
|
||||
}
|
||||
}
|
||||
} else if (!(order.at("fillSz").get<std::string>() == "0")) {
|
||||
utils::Uuid guid;
|
||||
std::string fill_id = guid.to_text_string();
|
||||
to_array(fill_id, &report.exchange_fill_id.value());
|
||||
utils::Uuid guid;
|
||||
std::string fill_id = guid.to_text_string();
|
||||
to_array(fill_id, &report.exchange_fill_id.value());
|
||||
}
|
||||
|
||||
|
||||
// report.transact_time = ExchangeTimeStampVar(std::stoll(order.at("uTime").get<std::string>()));
|
||||
ExchangeTimeStamp64 now = ExchangeTimeStamp64(datetime::unix_nano_now());
|
||||
report.transact_time = now;
|
||||
@@ -228,14 +229,14 @@ struct OkxExecutionGateway::PImpl {
|
||||
bts_assert_msgf(
|
||||
false, "Websocket stream client disconnected. {}", ec.message());
|
||||
}
|
||||
// fills execution report form basic_json and writes it to
|
||||
// buffered_exec_reps, which is picked up from the other thread
|
||||
// and passed over to the order infrastructure
|
||||
void _push_execution_report(const nlohmann::basic_json<> &order) {
|
||||
ExecutionReport er;
|
||||
get_exe_report(order, er);
|
||||
buffered_exec_reps.push(std::make_shared<ExecutionReport>(std::move(er)));
|
||||
}
|
||||
// fills execution report form basic_json and writes it to
|
||||
// buffered_exec_reps, which is picked up from the other thread
|
||||
// and passed over to the order infrastructure
|
||||
void _push_execution_report(const nlohmann::basic_json<> &order) {
|
||||
ExecutionReport er;
|
||||
get_exe_report(order, er);
|
||||
buffered_exec_reps.push(std::make_shared<ExecutionReport>(std::move(er)));
|
||||
}
|
||||
void on_message(const std::string &msg_str) {
|
||||
LOG(OrderMan, Info, "okxlistener::on_message. {}", msg_str);
|
||||
nlohmann::json msg;
|
||||
@@ -279,21 +280,22 @@ struct OkxExecutionGateway::PImpl {
|
||||
}
|
||||
|
||||
const auto &data = msg.at("data");
|
||||
|
||||
|
||||
|
||||
for (const nlohmann::basic_json<> &order : data) {
|
||||
int orderkey = 0;
|
||||
try {
|
||||
int orderkey = 0;
|
||||
try {
|
||||
int temp = std::stoi(order.at("clOrdId").get<std::string>());
|
||||
orderkey = temp;
|
||||
}catch (...) {
|
||||
}
|
||||
if(orderkey ==0){
|
||||
LOG(OrderMan, Error, "okxlistener::on_message GOT ER FOR ORDER NOT ENTERED FROM SYSTEM. {}", msg_str);
|
||||
} catch (...) {
|
||||
}
|
||||
if (orderkey == 0) {
|
||||
LOG(OrderMan, Error,
|
||||
"okxlistener::on_message GOT ER FOR ORDER NOT ENTERED FROM "
|
||||
"SYSTEM. {}",
|
||||
msg_str);
|
||||
continue;
|
||||
}
|
||||
_push_execution_report(order);
|
||||
}
|
||||
_push_execution_report(order);
|
||||
}
|
||||
}
|
||||
void start() {
|
||||
@@ -456,8 +458,8 @@ struct OkxExecutionGateway::PImpl {
|
||||
};
|
||||
void OkxExecutionGateway::start() { me_->start(); }
|
||||
OnGwStatusChange &OkxExecutionGateway::on_gw_status_change() {
|
||||
return me_->on_gw_status_change;
|
||||
}
|
||||
return me_->on_gw_status_change;
|
||||
}
|
||||
void OkxExecutionGateway::modify_order(
|
||||
const CancelReplaceOrderMsg &msg) { //confirm will have everything
|
||||
try {
|
||||
@@ -474,7 +476,7 @@ void OkxExecutionGateway::modify_order(
|
||||
std::to_string(msg.create_fields.quantity.full_value()));
|
||||
auto headers = OkxUtils::createHeaders(
|
||||
me_->api_key, me_->passphrase, me_->secret_key, "POST", REQUEST_PATH,
|
||||
me_->simulated_trading,body);
|
||||
me_->simulated_trading, body);
|
||||
// Generate and log the curl command
|
||||
std::string curlCommand = OkxUtils::generateCurlCommand(
|
||||
config::get<config::OkxExeCfg>().rest_url() + REQUEST_PATH, headers,
|
||||
@@ -488,7 +490,8 @@ void OkxExecutionGateway::modify_order(
|
||||
if (suc) {
|
||||
LOG(md, Info, "Http get succeeded {}", res.body);
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}", res.code, res.errors, res.body);
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}",
|
||||
res.code, res.errors, res.body);
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
const std::string err = ex.what();
|
||||
@@ -496,17 +499,17 @@ void OkxExecutionGateway::modify_order(
|
||||
}
|
||||
}
|
||||
void OkxExecutionGateway::dispatch_incoming_fix_messages() {
|
||||
if (me_->buffered_exec_reps.empty()) {
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<ExecutionReport> er;
|
||||
while (me_->buffered_exec_reps.try_pop(er)) {
|
||||
trace::CorID cid = {};
|
||||
LOG(OrderMan, Info,
|
||||
"OkxExecutionGateway::dispatch_incoming_fix_messages er: {} ",
|
||||
er->to_string());
|
||||
me_->cb(std::move(er), cid);
|
||||
}
|
||||
if (me_->buffered_exec_reps.empty()) {
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<ExecutionReport> er;
|
||||
while (me_->buffered_exec_reps.try_pop(er)) {
|
||||
trace::CorID cid = {};
|
||||
LOG(OrderMan, Info,
|
||||
"OkxExecutionGateway::dispatch_incoming_fix_messages er: {} ",
|
||||
er->to_string());
|
||||
me_->cb(std::move(er), cid);
|
||||
}
|
||||
}
|
||||
OnExeReport &OkxExecutionGateway::on_exe_report() { return me_->cb; }
|
||||
OnCancelReject &OkxExecutionGateway::on_cancel_reject() {
|
||||
@@ -538,12 +541,12 @@ void OkxExecutionGateway::launch_new_order(const CreateOrderMsg &msg) {
|
||||
const std::string ord_type =
|
||||
FIX::string_toLower(ord_full_name.substr(pos + suffix.size()));
|
||||
const std::string body = fmt::format(
|
||||
body_template, msg.security->okx().security_desc(),me_->tdmode, side, ord_type,
|
||||
price, quantity, msg.key);
|
||||
body_template, msg.security->okx().security_desc(), me_->tdmode, side,
|
||||
ord_type, price, quantity, msg.key);
|
||||
http::HttpResponse res;
|
||||
auto headers = OkxUtils::createHeaders(
|
||||
me_->api_key, me_->passphrase, me_->secret_key, "POST", REQUEST_PATH,
|
||||
me_->simulated_trading,body);
|
||||
me_->simulated_trading, body);
|
||||
// Generate and log the curl command
|
||||
std::string curlCommand = OkxUtils::generateCurlCommand(
|
||||
config::get<config::OkxExeCfg>().rest_url() + REQUEST_PATH, headers,
|
||||
@@ -556,30 +559,33 @@ void OkxExecutionGateway::launch_new_order(const CreateOrderMsg &msg) {
|
||||
const auto &[suc, top_msg] = OkxUtils::orderAccepted(res.body);
|
||||
|
||||
if (suc) {
|
||||
LOG(md, Info, "Http get succeeded {}", res.body);
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_PENDING_NEW;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_PENDING_NEW;
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}", res.code, res.errors, res.body);
|
||||
OkxUtils::populateCreateOrderFields(er, msg);
|
||||
er.price = msg.price;
|
||||
er.quantity = msg.quantity;
|
||||
er.filled_quantity = 0;
|
||||
er.last_shares = 0;
|
||||
er.leg_security = nullptr;
|
||||
er.avg_price = Price(0);
|
||||
ExchangeTimeStamp64 now = ExchangeTimeStamp64(datetime::unix_nano_now());
|
||||
er.transact_time = now;
|
||||
er.order_key = msg.key;
|
||||
const auto &[id, ts, ex_msg] = OkxUtils::extractOrderInfo(res.body);
|
||||
er.exchange_order_id = ExchangeOrderID{OkxUtils::stringToFixedArray(id)};
|
||||
er.exec_type = api::orderman::ExecType::EXEC_TYPE_REJECTED;
|
||||
er.order_status = api::orderman::NATIVE_ORDER_STATUS_REJECTED;
|
||||
er.msg = ex_msg + " " + top_msg;
|
||||
me_->buffered_exec_reps.push(
|
||||
std::make_shared<ExecutionReport>(std::move(er)));
|
||||
LOG(md, Info, "Http get succeeded {}", res.body);
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_PENDING_NEW;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_PENDING_NEW;
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}",
|
||||
res.code, res.errors, res.body);
|
||||
OkxUtils::populateCreateOrderFields(er, msg);
|
||||
er.price = msg.price;
|
||||
er.quantity = msg.quantity;
|
||||
er.filled_quantity = 0;
|
||||
er.last_shares = 0;
|
||||
er.leg_security = nullptr;
|
||||
er.avg_price = Price(0);
|
||||
ExchangeTimeStamp64 now =
|
||||
ExchangeTimeStamp64(datetime::unix_nano_now());
|
||||
er.transact_time = now;
|
||||
er.order_key = msg.key;
|
||||
const auto &[id, ts, ex_msg] = OkxUtils::extractOrderInfo(res.body);
|
||||
er.exchange_order_id =
|
||||
ExchangeOrderID{OkxUtils::stringToFixedArray(id)};
|
||||
er.exec_type = api::orderman::ExecType::EXEC_TYPE_REJECTED;
|
||||
er.order_status = api::orderman::NATIVE_ORDER_STATUS_REJECTED;
|
||||
er.msg = ex_msg + " " + top_msg;
|
||||
me_->buffered_exec_reps.push(
|
||||
std::make_shared<ExecutionReport>(std::move(er)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Shut down all reactors if they exist.
|
||||
catch (const std::exception &ex) {
|
||||
const std::string err = ex.what();
|
||||
@@ -605,7 +611,7 @@ void OkxExecutionGateway::cancel_order(const CancelOrderMsg &msg) {
|
||||
body_template, msg.security->okx().security_desc(), msg.key);
|
||||
auto headers = OkxUtils::createHeaders(
|
||||
me_->api_key, me_->passphrase, me_->secret_key, "POST", REQUEST_PATH,
|
||||
me_->simulated_trading,body);
|
||||
me_->simulated_trading, body);
|
||||
// Generate and log the curl command
|
||||
std::string curlCommand = OkxUtils::generateCurlCommand(
|
||||
config::get<config::OkxExeCfg>().rest_url() + REQUEST_PATH, headers,
|
||||
@@ -630,7 +636,8 @@ void OkxExecutionGateway::cancel_order(const CancelOrderMsg &msg) {
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_PENDING_CANCEL;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_PENDING_CANCEL;
|
||||
} else {
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}", res.code, res.errors, res.body);
|
||||
LOG(md, Info, "Http get failed code: {}, errors: {}, body: {}",
|
||||
res.code, res.errors, res.body);
|
||||
// er.exec_type = api::orderman::ExecType::EXEC_TYPE_REJECTED;
|
||||
// er.order_status = api::orderman::NATIVE_ORDER_STATUS_REJECTED;
|
||||
// er.msg = ex_msg + " " + top_msg;
|
||||
@@ -643,8 +650,7 @@ void OkxExecutionGateway::cancel_order(const CancelOrderMsg &msg) {
|
||||
OkxUtils::handleOkException("Cacnel order", err);
|
||||
}
|
||||
}
|
||||
} // namespace bts::orderman::okxexe
|
||||
|
||||
} // namespace bts::orderman
|
||||
|
||||
// ExecutionReport OkxExecutionAdapter::fire_dummy_modify_order_report(CancelReplaceOrderMsg msg) {
|
||||
// ExecutionReport *er_p = me_->create_exe_ptr();
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "lib/md/MDProducer.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/md/Shm/MDStructure.h"
|
||||
#include "lib/orderman/CancelOrderMsg.h"
|
||||
#include "lib/orderman/CreateOrderMsg.h"
|
||||
#include "lib/orderman/OrderMsg.h"
|
||||
#include "lib/orderman/events/NewAdminDataEvent.h"
|
||||
#include "lib/orderman/events/NewSecuritiesEvent.h"
|
||||
@@ -180,6 +182,10 @@ struct SEGOrderState {
|
||||
last_filled_qty = 0;
|
||||
last_filled_price = Price(os::nan());
|
||||
}
|
||||
bool is_ioc() const {
|
||||
return crt_msg.time_in_force ==
|
||||
api::orderman::TimeInForce::TIME_IN_FORCE_IOC;
|
||||
}
|
||||
};
|
||||
|
||||
struct SEGTradeEntry {
|
||||
@@ -226,8 +232,10 @@ struct SEGSecurityData {
|
||||
const CancelReplaceOrderMsg &cxlr_msg =
|
||||
std::get<CancelReplaceOrderMsg>(msg);
|
||||
SEGOrderState *seg_os = find_order(cxlr_msg.create_fields.key);
|
||||
if(seg_os == nullptr){
|
||||
LOG(OrderMan, Info, "SimExecutionGateway::apply_order_action tried updating unkown order");
|
||||
if (seg_os == nullptr) {
|
||||
LOG(OrderMan, Info,
|
||||
"SimExecutionGateway::apply_order_action tried updating unkown "
|
||||
"order");
|
||||
return {ActionResult::NoOp, nullptr};
|
||||
}
|
||||
auto action_result = seg_os->apply_change(cxlr_msg);
|
||||
@@ -235,8 +243,10 @@ struct SEGSecurityData {
|
||||
} else if (std::holds_alternative<CancelOrderMsg>(msg)) {
|
||||
const CancelOrderMsg &cxl_msg = std::get<CancelOrderMsg>(msg);
|
||||
SEGOrderState *seg_os = find_order(cxl_msg.key);
|
||||
if(seg_os == nullptr){
|
||||
LOG(OrderMan, Info, "SimExecutionGateway::apply_order_action tried canceling unkown order");
|
||||
if (seg_os == nullptr) {
|
||||
LOG(OrderMan, Info,
|
||||
"SimExecutionGateway::apply_order_action tried canceling "
|
||||
"unkown order");
|
||||
return {ActionResult::NoOp, nullptr};
|
||||
}
|
||||
auto action_result = seg_os->apply_cxl(cxl_msg);
|
||||
@@ -578,6 +588,14 @@ bts::orderman::Book SimExecutionGateway::_match_order(
|
||||
if (crosses_opp_side) {
|
||||
return _cross_order(book, seg_os);
|
||||
} else {
|
||||
if (seg_os.is_ioc()) {
|
||||
CancelOrderMsg cxl_msg;
|
||||
cxl_msg.key = seg_os.ord_key();
|
||||
seg_os.apply_cxl(cxl_msg);
|
||||
_push_execution_report(seg_os);
|
||||
// generate cancel execution report
|
||||
return book;
|
||||
}
|
||||
return _work_order(book, seg_os);
|
||||
}
|
||||
}
|
||||
@@ -651,7 +669,8 @@ SEGSecurityData *SimExecutionGateway::_find_add_security_entry(
|
||||
void SimExecutionGateway::_push_execution_report(const SEGOrderState &seg_os) {
|
||||
ExecutionReport er;
|
||||
fill_execution_report(seg_os, er);
|
||||
me->buffered_exec_reps.push(std::make_shared<ExecutionReport>(std::move(er)));
|
||||
me->buffered_exec_reps.push(
|
||||
std::make_shared<ExecutionReport>(std::move(er)));
|
||||
}
|
||||
|
||||
void SimExecutionGateway::_write_book(SecurityKey key) {
|
||||
|
||||
@@ -156,12 +156,15 @@ void SpreaderOrder::_on_time(const bts::mercury::TimerEvent &t_event) {
|
||||
}
|
||||
}
|
||||
void SpreaderOrder::_on_book_update(const BookUpdateEvent &book_event) {
|
||||
// TODO: rmeove
|
||||
LOG(OrderMan, Diag,
|
||||
"SpreaderOrder::_on_book_update skey: {} bid: {}/{} a: {}/{}",
|
||||
book_event.key(), book_event.book.bid().at(0).price(),
|
||||
book_event.book.bid().at(0).size(), book_event.book.ask().at(0).price(),
|
||||
book_event.book.ask().at(0).size());
|
||||
if (book_event.key() == _bookkeeping_data().spread_sec_key()) {
|
||||
_bookkeeping_data().spread_book = book_event.book;
|
||||
return;
|
||||
}
|
||||
if (!_active)
|
||||
return;
|
||||
auto scoped = _order_services->log_scope(
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader_states/SpreaderWaitingForInitialDataStateWorker.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader_states/SpreaderWorkingStateWorker.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
#include "lib/utils/is_unittest_environment.h"
|
||||
#include <memory>
|
||||
@@ -107,7 +108,7 @@ class SpreaderOrder : public Order, public ISpreaderManager {
|
||||
public:
|
||||
// inherited function to return the OrderDefinition. asserts
|
||||
// if on_init_new has not been called yet
|
||||
const api::orderman::OrderDefinition &definition() const;
|
||||
const api::orderman::OrderDefinition &definition() const override;
|
||||
// this is the construction, can be slow
|
||||
void on_init_new(
|
||||
const bts::api::orderman::OrderDefinition &order_def,
|
||||
@@ -136,8 +137,19 @@ class SpreaderOrder : public Order, public ISpreaderManager {
|
||||
bts::orderman::OrderKey spreader_order_key() const override { return key(); }
|
||||
bts::TimeStamp current_time() const override { return _curr_timestamp; }
|
||||
const bts::orderman::Book &get_book(size_t leg_index) const override {
|
||||
return _bookkeeping_data().get_leg_data(leg_index).book();
|
||||
const SpreaderLegData &leg_data =
|
||||
_bookkeeping_data().get_leg_data(leg_index);
|
||||
const auto &rv = leg_data.book();
|
||||
return rv;
|
||||
//return _bookkeeping_data().get_leg_data(leg_index).book();
|
||||
}
|
||||
|
||||
const bts::orderman::Book &get_spread_book() const override {
|
||||
const auto &opt_book = _bookkeeping_data().spread_book;
|
||||
bts_assert(opt_book.has_value());
|
||||
return opt_book.value();
|
||||
}
|
||||
|
||||
const LegPropertyData &get_leg_data(size_t leg_index) const override {
|
||||
return _bookkeeping_data().get_leg_data(leg_index).leg_property_data();
|
||||
}
|
||||
@@ -148,6 +160,10 @@ class SpreaderOrder : public Order, public ISpreaderManager {
|
||||
inline bool in_cache_warming_cycle() const override {
|
||||
return _cw_helper.in_cache_warming_cycle;
|
||||
}
|
||||
inline bts::spark::ExecutionStrategy::SpreaderType
|
||||
get_spreader_quoting_type() const override {
|
||||
return _bookkeeping_data().spreader_quoting_type();
|
||||
}
|
||||
// this is called by the SpreaderChildOrderState
|
||||
void place_order(
|
||||
ChildOrder &child_order,
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#pragma once
|
||||
#include "SpreaderFractionalQtyHelper.h"
|
||||
#include "lib/api/services/OrderService.pb.h"
|
||||
#include "lib/domain_model/SecurityKey.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/orderman/ChildOrder.h"
|
||||
#include "lib/orderman/orderman_utils/Book.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include <optional>
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -18,10 +21,17 @@ class IAlternateOrderGateway;
|
||||
// ii. create new quoter order
|
||||
class ISpreaderManager {
|
||||
public:
|
||||
// definition() was added when we expanded the spreader to add reverse hedging and sniper.
|
||||
// that needed spreader sid etc, which is all in the definition. Also spreader_order_key() can
|
||||
// retired
|
||||
virtual const api::orderman::OrderDefinition &definition() const = 0;
|
||||
virtual bts::orderman::OrderKey spreader_order_key() const = 0;
|
||||
virtual bts::TimeStamp current_time() const = 0;
|
||||
// this is a reference to the original book structure
|
||||
virtual const bts::orderman::Book &get_book(size_t leg_index) const = 0;
|
||||
// it returns the valid spread book, for quoting tsrategies (non re-quoting) that need the
|
||||
// the spread book. otherwise this function asserts
|
||||
virtual const bts::orderman::Book &get_spread_book() const = 0;
|
||||
// the caller can keep a reference to the returned type forever. the
|
||||
// data in the returned type is all const
|
||||
virtual const LegPropertyData &get_leg_data(size_t leg_index) const = 0;
|
||||
@@ -41,6 +51,8 @@ class ISpreaderManager {
|
||||
// (however do as much as they can to keep the instruction
|
||||
// cache warm)
|
||||
virtual bool in_cache_warming_cycle() const = 0;
|
||||
virtual bts::spark::ExecutionStrategy::SpreaderType
|
||||
get_spreader_quoting_type() const = 0;
|
||||
// orders are placed through the ISpreaderManager. Eventhough ChildOrder has
|
||||
// the facility to do that directly, we want to control all order activity
|
||||
// through one central place
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "LegPropertyData.h"
|
||||
#include "ISpreaderManager.h"
|
||||
#include "SpreaderUtils.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -10,11 +12,35 @@ LegPropertyData::LegPropertyData(
|
||||
const bts::api::ContractLeg &leg_contract,
|
||||
const bts::spark::LegSpreaderParams &leg_params,
|
||||
api::Side trading_side,
|
||||
bts::spark::ExecutionStrategy::SpreaderType spreader_quoting_type,
|
||||
bts::api::SyntheticContract::PriceCalc price_calc,
|
||||
double qty_tick_size)
|
||||
: _leg_index(leg_index), _leg_contract(leg_contract),
|
||||
_leg_params(leg_params), _trading_side(trading_side),
|
||||
|
||||
_price_calc(price_calc), _qty_tick_size(qty_tick_size) {
|
||||
switch (spreader_quoting_type) {
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REQUOTE: {
|
||||
_is_active_quoting = leg_params.has_quote_params();
|
||||
break;
|
||||
}
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REVERSE_HEDGE: {
|
||||
_is_active_quoting = leg_params.has_reverse_hedge_quote_params();
|
||||
break;
|
||||
}
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_SNIPER: {
|
||||
_is_active_quoting = leg_params.has_sniper_quote_params();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
bts_assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(OrderMan, Info,
|
||||
"LegPropertyData.cons leg_idx: "
|
||||
"{} sec_key: {} side: {}",
|
||||
|
||||
@@ -19,6 +19,7 @@ class LegPropertyData {
|
||||
const api::Side _trading_side;
|
||||
const bts::api::SyntheticContract::PriceCalc _price_calc;
|
||||
const double _qty_tick_size = 1.0;
|
||||
bool _is_active_quoting;
|
||||
|
||||
public:
|
||||
LegPropertyData(
|
||||
@@ -26,6 +27,9 @@ class LegPropertyData {
|
||||
const bts::api::ContractLeg &leg_contract,
|
||||
const bts::spark::LegSpreaderParams &leg_params,
|
||||
api::Side trading_side,
|
||||
bts::spark::ExecutionStrategy::SpreaderType spreader_quoting_type =
|
||||
bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REQUOTE,
|
||||
bts::api::SyntheticContract::PriceCalc price_calc =
|
||||
bts::api::SyntheticContract::PRICECALC_STANDARD,
|
||||
double qty_tick_size = 1.0);
|
||||
@@ -50,7 +54,9 @@ class LegPropertyData {
|
||||
return _leg_contract.security().contract_spec().low_tick();
|
||||
}
|
||||
double qty_tick_size() const { return _qty_tick_size; }
|
||||
bool is_active_quoting() const { return _leg_params.is_active_quoting(); }
|
||||
// TODO: is_quoting
|
||||
//bool is_active_quoting() const { return _leg_params.is_active_quoting(); }
|
||||
bool is_active_quoting() const { return _is_active_quoting; }
|
||||
bool is_net_change() const {
|
||||
return _price_calc == bts::api::SyntheticContract::PRICECALC_NET_CHANGE;
|
||||
}
|
||||
|
||||
@@ -76,8 +76,7 @@ SingleLegQuoter::SingleLegQuoter(SingleLegQuoter &&other)
|
||||
bts_assert(false);
|
||||
}
|
||||
/*********************************************************************************/
|
||||
/*********************************spreader
|
||||
* calls**********************************/
|
||||
/*********************************spreader calls**********************************/
|
||||
/*********************************************************************************/
|
||||
void SingleLegQuoter::one_time_activate(Price price, Quantity quantity) {
|
||||
bts_assert(_active_quoting);
|
||||
@@ -274,7 +273,9 @@ void SingleLegQuoter::_transform_to_WAITING_FOR_IOC() {
|
||||
_switch_state(&_waiting_for_ioc_worker);
|
||||
}
|
||||
void SingleLegQuoter::_transform_to_WAITING_FOR_FIRST_ACK_CANCELLED() {
|
||||
bts_assert(_worker->state() == QuoterState::WAITING_FOR_FIRST_ACK);
|
||||
bts_assert(
|
||||
_worker->state() == QuoterState::WAITING_FOR_FIRST_ACK ||
|
||||
_worker->state() == QuoterState::WAITING_FOR_IOC);
|
||||
_switch_state(&_waiting_for_first_ack_cancelled_state_worker);
|
||||
}
|
||||
void SingleLegQuoter::_transform_to_WORKING() {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/LegPropertyData.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderFractionalQtyHelper.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -41,6 +42,11 @@ SpreaderBookkeepingData::SpreaderBookkeepingData(
|
||||
_leg_data.emplace_back(
|
||||
spreader_pao_services, spreader_order_key, _n_legs, spreader_manager,
|
||||
quoter_ord_defs[i], hedger_ord_defs[i], leg_property_data);
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderBookkeepingData::cons leg_idx: {} quoter_ord_def: {} "
|
||||
"hedger_ord_defs: {}",
|
||||
i, utils::pb::to_string(quoter_ord_defs[i]),
|
||||
utils::pb::to_string(hedger_ord_defs[i]));
|
||||
bts_assert(
|
||||
_sec_key_to_index.find(leg_property_data.security_key()) ==
|
||||
_sec_key_to_index.end());
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
#include "lib/domain_model/SecurityKey.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/orderman/orderman_utils/Book.h"
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "NLegsHedgeRecompData.h"
|
||||
#include "SpreaderLegData.h"
|
||||
@@ -14,6 +17,7 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderPreActivationOrderServices.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/hedger/HedgerManager.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/hedger/UnhedgedDelta.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -42,6 +46,9 @@ class SpreaderBookkeepingData {
|
||||
NLegsHedgeRecompData _hedge_recomp_data;
|
||||
SpreaderFractionalQtyHelper _fqty_helper;
|
||||
|
||||
public:
|
||||
std::optional<Book> spread_book;
|
||||
|
||||
private:
|
||||
size_t _calc_n_quoting_legs(const std::vector<LegPropertyData> &legs);
|
||||
|
||||
@@ -166,6 +173,15 @@ class SpreaderBookkeepingData {
|
||||
}
|
||||
size_t n_quoting_legs() const { return _n_quoting_legs; }
|
||||
SpreaderFractionalQtyHelper &fqty_helper() { return _fqty_helper; }
|
||||
SecurityKey spread_sec_key() const {
|
||||
return SecurityKey(_order_def.security_key());
|
||||
}
|
||||
bts::spark::ExecutionStrategy::SpreaderType spreader_quoting_type() const {
|
||||
return _order_def.custom_def()
|
||||
.spreader()
|
||||
.execution_strategy()
|
||||
.spreader_type();
|
||||
}
|
||||
};
|
||||
} // namespace orderman
|
||||
} // namespace bts
|
||||
@@ -96,7 +96,10 @@ class SpreaderLegData {
|
||||
bts_assert(_is_quoting);
|
||||
return *_quoter;
|
||||
}
|
||||
const bts::orderman::Book &book() const { return _book; }
|
||||
const bts::orderman::Book &book() const {
|
||||
// book
|
||||
return _book;
|
||||
}
|
||||
Price settlement_price() const { return Price(_settlement_price.price()); }
|
||||
bool settlement_populated() const {
|
||||
return !os::is_nan(_settlement_price.price());
|
||||
@@ -162,6 +165,11 @@ class SpreaderLegData {
|
||||
book, _settlement_price, _leg_property_data.tick_size(),
|
||||
_leg_property_data.md_type(),
|
||||
bts::api::SyntheticContract::PRICECALC_STANDARD, _book);
|
||||
// LOG(OrderMan, Info,
|
||||
// "SpreaderLegData::update_book index: {} lpd_key: {} book: {} book "
|
||||
// "key: {}",
|
||||
// _leg_property_data.leg_index(), _leg_property_data.security_key(),
|
||||
// book, book.security_key());
|
||||
}
|
||||
void update_settlement_price(md::IntPrice price) {
|
||||
_settlement_price = price;
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
#include "SpreaderUtils.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/orderman/events/BookUpdateEvent.h"
|
||||
#include "lib/orderman/orderman_utils/Book.h"
|
||||
#include "lib/orderman/orders/PreActivationOrderServices.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderOrderBuilder.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/external_interfacing/SpreaderPreActivationOrderServices.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include "lib/utils/PBUtils.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include <sstream>
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -65,6 +69,28 @@ bool SpreaderUtils::resolve_synthetic_spread(
|
||||
std::vector<bts::api::orderman::OrderDefinition> &out_quoter_defs,
|
||||
std::vector<bts::api::orderman::OrderDefinition> &out_hedger_defs,
|
||||
bool resolve_synthetic) {
|
||||
LOG(OrderMan, Info, "g/ {}",
|
||||
utils::pb::to_string(order_def));
|
||||
auto get_quote_time_enforce =
|
||||
[&](const spark::ExecutionStrategy &exec_strat,
|
||||
const spark::LegSpreaderParams &q_leg_params) {
|
||||
switch (exec_strat.spreader_type()) {
|
||||
case spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REQUOTE:
|
||||
case spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_SNIPER:
|
||||
return order_def.time_in_force();
|
||||
case spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REVERSE_HEDGE:
|
||||
if (q_leg_params.has_reverse_hedge_quote_params())
|
||||
return bts::api::orderman::TimeInForce::TIME_IN_FORCE_IOC;
|
||||
else
|
||||
return order_def.time_in_force();
|
||||
default:
|
||||
bts_assert(false);
|
||||
return order_def.time_in_force();
|
||||
}
|
||||
};
|
||||
bts_assert(
|
||||
order_def.has_custom_def() && order_def.custom_def().has_spreader());
|
||||
const bts::api::Security *sec_ptr =
|
||||
@@ -128,27 +154,32 @@ bool SpreaderUtils::resolve_synthetic_spread(
|
||||
->mutable_limit()
|
||||
->MergeFrom(api::orderman::LimitOrderDefinition());
|
||||
}
|
||||
|
||||
if (leg_params.quote_params().has_quote_hidden())
|
||||
quoter_order_def.set_time_in_force(
|
||||
bts::api::orderman::TimeInForce::TIME_IN_FORCE_IOC);
|
||||
else
|
||||
quoter_order_def.set_time_in_force(
|
||||
order_def.time_in_force());
|
||||
auto tif =
|
||||
get_quote_time_enforce(execution_strategy, leg_params);
|
||||
quoter_order_def.set_time_in_force(tif);
|
||||
// hedger order def
|
||||
api::orderman::OrderDefinition hedger_order_def =
|
||||
quoter_order_def;
|
||||
hedger_order_def.mutable_custom_def()
|
||||
->mutable_limit()
|
||||
->MergeFrom(api::orderman::LimitOrderDefinition());
|
||||
quoter_order_def.set_time_in_force(order_def.time_in_force());
|
||||
//quoter_order_def.set_time_in_force(order_def.time_in_force());
|
||||
hedger_order_def.set_sub_type(
|
||||
bts::api::orderman::OrderSubType::
|
||||
ORDER_SUB_TYPE_HEDGING_LEG);
|
||||
LegPropertyData leg_property_data(
|
||||
leg_idx, leg, leg_params, leg_order_side,
|
||||
order_def.custom_def()
|
||||
.spreader()
|
||||
.execution_strategy()
|
||||
.spreader_type(),
|
||||
sec.synthetic().price_calc());
|
||||
out_resolved.push_back(leg_property_data);
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::resolve_synthetic_spread idx: {} "
|
||||
"quoter_order_def: {}",
|
||||
out_quoter_defs.size(),
|
||||
utils::pb::to_string(quoter_order_def));
|
||||
out_quoter_defs.push_back(quoter_order_def);
|
||||
out_hedger_defs.push_back(hedger_order_def);
|
||||
leg_idx++;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "lib/domain_model/Security.pb.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/jetfix/codec/FieldDefinitions.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/md/IntPrice.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/md/Shm/MDStructure.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <random>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace bts {
|
||||
@@ -312,8 +314,10 @@ class SpreaderUtils {
|
||||
opp_side[0].price(), price.value(), tick_size));
|
||||
}
|
||||
// find the top of the synthetic book
|
||||
static Price top_of_book_price(const ISpreaderManager &, api::Side) {
|
||||
Price rv(os::nan());
|
||||
static std::tuple<Price, Quantity> top_of_book_price(
|
||||
const ISpreaderManager &, api::Side) {
|
||||
//TODO
|
||||
std::tuple<Price, Quantity> rv{os::nan(), Quantity::create_new(0.0)};
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -459,6 +463,75 @@ class SpreaderUtils {
|
||||
}
|
||||
}
|
||||
|
||||
// this is a general purpose function that tells if the book is through the
|
||||
// order price by a certian number of ticks
|
||||
static int book_through_order_price_nticks(
|
||||
Price order_price,
|
||||
api::Side order_side,
|
||||
double tick_size,
|
||||
const Book &book) {
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::book_through_order_price_nticks: order_price: {} "
|
||||
"order_side: {} tick_size: {} -- bid: {}/{} ask: {}/{}",
|
||||
order_price, static_cast<int>(order_side), tick_size,
|
||||
book.bid().at(0).price(), book.bid().at(0).size(),
|
||||
book.ask().at(0).price(), book.ask().at(0).size());
|
||||
if (order_side == api::SIDE_BUY) {
|
||||
const md::PriceSize &top_ask = book.ask()[0];
|
||||
if (top_ask.size() == 0)
|
||||
return -100;
|
||||
int t_diff = securities::price_diff_to_ticks(
|
||||
top_ask.price(), order_price.value(), tick_size);
|
||||
return t_diff;
|
||||
} else {
|
||||
const md::PriceSize &top_bid = book.bid()[0];
|
||||
if (top_bid.size() == 0)
|
||||
return -100;
|
||||
int t_diff = securities::price_diff_to_ticks(
|
||||
order_price.value(), top_bid.price(), tick_size);
|
||||
return t_diff;
|
||||
}
|
||||
}
|
||||
|
||||
static Price compute_order_price_through_book(
|
||||
const Book &book, api::Side order_side, double tick_size, int n_ticks) {
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::compute_order_price_through_book tick_size: {} "
|
||||
"n_ticks: {}",
|
||||
tick_size, n_ticks);
|
||||
switch (order_side) {
|
||||
case api::Side::SIDE_BUY: {
|
||||
if (n_ticks >= 0) {
|
||||
double top_ask = book.ask()[0].price();
|
||||
return Price(top_ask + tick_size * n_ticks);
|
||||
//return Price(book.ask()[n_ticks].price());
|
||||
} else {
|
||||
double top_bid = book.bid()[0].price();
|
||||
return Price(top_bid - tick_size * n_ticks);
|
||||
//return Price(book.bid()[std::abs(n_ticks)].price());
|
||||
}
|
||||
}
|
||||
case api::Side::SIDE_SELL: {
|
||||
if (n_ticks >= 0) {
|
||||
double top_bid = book.bid()[0].price();
|
||||
double rv = top_bid - tick_size * n_ticks;
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderUtils::compute_order_price_through_book top_bid: {} "
|
||||
"rv: {}",
|
||||
top_bid, rv);
|
||||
return Price(rv);
|
||||
} else {
|
||||
double top_ask = book.ask()[0].price();
|
||||
return Price(top_ask + tick_size * n_ticks);
|
||||
}
|
||||
}
|
||||
default: {
|
||||
bts_assert(false);
|
||||
return Price(os::nan());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// pre-hedge params ////////////////////////////////
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
+104
@@ -1,8 +1,18 @@
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterWaitingForSizeStateWorker.h"
|
||||
#include "lib/domain_model/Security.pb.h"
|
||||
#include "lib/domain_model/common.h"
|
||||
#include "lib/logging/logging.h"
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/orderman/orderman_utils/Book.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/ISpreaderManager.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/LegPropertyData.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SingleLegQuoter.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderChildOrderState.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/SpreaderUtils.h"
|
||||
#include "lib/orderman/orders/spreader_orders/spreader/quoter/quoter_states/QuoterState.h"
|
||||
#include "lib/os/os.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
|
||||
namespace bts {
|
||||
namespace orderman {
|
||||
@@ -53,12 +63,105 @@ void QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act() {
|
||||
"target reached, transforming to end",
|
||||
_quoter->_key().value());
|
||||
_quoter->_transform_to_END();
|
||||
return;
|
||||
} else {
|
||||
auto spreader_q_type = _quoter->_spreader.get_spreader_quoting_type();
|
||||
switch (spreader_q_type) {
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REQUOTE: {
|
||||
Price out_price;
|
||||
Quantity out_quantity;
|
||||
_quoter->_compute_price_quantity(out_price, out_quantity);
|
||||
if (out_quantity.value() > 0) {
|
||||
// only applicable for > 2 legged spreads
|
||||
_quoter->_commit_drivers(out_price);
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker (requoting) sending order "
|
||||
"key:{} price:{} quantity:{}",
|
||||
_quoter->_key(), out_price, out_quantity);
|
||||
// this is the only place where a quoter order is entered
|
||||
_quoter->_place_order(out_price, out_quantity);
|
||||
_quoter->_transform_to_WAITING_FOR_FIRST_ACK();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REVERSE_HEDGE: {
|
||||
auto is_book_populated = [&](const Book &leg_book, api::Side bs) {
|
||||
const auto &book_side = leg_book.side(bs);
|
||||
return !os::is_nan(book_side.at(0).price());
|
||||
};
|
||||
const LegPropertyData &leg_data = _quoter->_this_leg_data;
|
||||
bts_assert(leg_data.leg_params().has_reverse_hedge_quote_params());
|
||||
const auto &rev_hedge_qparams =
|
||||
leg_data.leg_params().reverse_hedge_quote_params();
|
||||
int n_ticks = rev_hedge_qparams.n_ticks();
|
||||
const Book &spread_book = _quoter->_spreader.get_spread_book();
|
||||
auto spread_side = _quoter->_spreader.definition().side();
|
||||
int book_through_ticks =
|
||||
SpreaderUtils::book_through_order_price_nticks(
|
||||
_quoter->_price_quantity_state.target_spread_price(),
|
||||
// TODO (get it from the spread synth sec)
|
||||
spread_side, 0.1, spread_book);
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act("
|
||||
"reverse hedge) "
|
||||
"n_ticks: {} book_through_ticks: {}",
|
||||
n_ticks, book_through_ticks);
|
||||
if (book_through_ticks >= n_ticks) {
|
||||
// qty, shoot full size? (can min it by max available on hedge leg)
|
||||
//auto spr_qty = _quoter->_price_quantity_state.out_quantity();
|
||||
// needs to be reduced by filled qty
|
||||
// qty: (this is what remains, reduced by how can be leaned on)
|
||||
auto order_qty = _quoter->_price_quantity_state.remaining_to_fill();
|
||||
auto reduce_by_available_hedge = [&](auto leg_qty) {
|
||||
return leg_qty;
|
||||
};
|
||||
order_qty = reduce_by_available_hedge(order_qty);
|
||||
// price: (nticks into the opposite market)
|
||||
const Book &leg_book =
|
||||
_quoter->_spreader.get_book(leg_data.leg_index());
|
||||
bool leg_book_populated = is_book_populated(
|
||||
leg_book, SpreaderUtils::invert_side(leg_data.trading_side()));
|
||||
if (!leg_book_populated) {
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act "
|
||||
"(RH), quoting leg book is empty, not firing order");
|
||||
return;
|
||||
}
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act "
|
||||
"leg_book: {} k: {}",
|
||||
leg_book, leg_book.security_key());
|
||||
Price order_price = SpreaderUtils::compute_order_price_through_book(
|
||||
leg_book, leg_data.trading_side(), leg_data.tick_size(),
|
||||
n_ticks);
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker sending order in reverse "
|
||||
"hedging mode key: {} price: {} quantity: {}",
|
||||
_quoter->_key(), order_price, order_qty);
|
||||
_quoter->_place_order(order_price, order_qty);
|
||||
_quoter->_transform_to_WAITING_FOR_IOC();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_SNIPER: {
|
||||
bts_assert(
|
||||
_quoter->_this_leg_data.leg_params().has_sniper_quote_params());
|
||||
return;
|
||||
}
|
||||
default: {
|
||||
bts_assert(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Price out_price;
|
||||
Quantity out_quantity;
|
||||
_quoter->_compute_price_quantity(out_price, out_quantity);
|
||||
_quoter->_adjust_for_hidden_order(out_price, out_quantity);
|
||||
if (out_quantity.value() > 0) {
|
||||
// only applicable for > 2 legged spreads
|
||||
_quoter->_commit_drivers(out_price);
|
||||
LOG(OrderMan, Info,
|
||||
"QuoterWaitingForSizeStateWorker sending order "
|
||||
@@ -67,6 +170,7 @@ void QuoterWaitingForSizeStateWorker::_longpath_analyze_and_act() {
|
||||
// this is the only place where a quoter order is entered
|
||||
_quoter->_place_order(out_price, out_quantity);
|
||||
if (_quoter->_hidden_order)
|
||||
// TODO:sniper
|
||||
_quoter->_transform_to_WAITING_FOR_IOC();
|
||||
else
|
||||
_quoter->_transform_to_WAITING_FOR_FIRST_ACK();
|
||||
|
||||
+8
-1
@@ -129,13 +129,20 @@ void SpreaderStartStateWorker::on_activate(
|
||||
_spreader->_on_child_order_update(os);
|
||||
});
|
||||
// 5. sub to market data
|
||||
// subsribe to spread book ()
|
||||
auto spr_sk = _spreader->_bookkeeping_data().spread_sec_key();
|
||||
order_services.order_services().subscribe_to_book(
|
||||
spr_sk, [this](const BookUpdateEvent &bk_event) {
|
||||
_spreader->_on_book_update(bk_event);
|
||||
});
|
||||
for (size_t l_idx = 0; l_idx < _spreader->_bookkeeping_data().n_legs();
|
||||
l_idx++) {
|
||||
const LegPropertyData &leg_prop = _spreader->_bookkeeping_data()
|
||||
.get_leg_data(l_idx)
|
||||
.leg_property_data();
|
||||
LOG(OrderMan, Info,
|
||||
"SpreaderStartStateWorker::on_activate subbing to book sec_key: "
|
||||
"SpreaderStartStateWorker::on_activate subbing to book "
|
||||
"sec_key: "
|
||||
"{}",
|
||||
leg_prop.security_key());
|
||||
order_services.order_services().subscribe_to_book(
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "lib/md/PriceSize.h"
|
||||
#include "lib/orderman/orderman_utils/orderman_common.h"
|
||||
#include "lib/orderman/securities/ISecurityDB.h"
|
||||
#include "lib/sparkproto/SparkProtos.pb.h"
|
||||
#include "lib/utils/bts_assert.h"
|
||||
#include "lib/utils/bts_chrono.h"
|
||||
//#include "lib/utils/REQUIRE.h"
|
||||
@@ -133,6 +134,14 @@ class SpreaderManagerForTest : public ISpreaderManager {
|
||||
const bts::orderman::Book &get_book(size_t leg_index) const override {
|
||||
return _bookkeeping_data.get_leg_data(leg_index).book();
|
||||
}
|
||||
const bts::orderman::Book &get_spread_book() const override {
|
||||
// TODO: since its not used in tests, we just do this ot pass the tests
|
||||
return _bookkeeping_data.spread_book.value();
|
||||
//return get_book(0);
|
||||
}
|
||||
const api::orderman::OrderDefinition &definition() const override {
|
||||
return _bookkeeping_data.order_def();
|
||||
}
|
||||
// the caller can keep a reference to the returned type forever. the
|
||||
// data in the returned type is all const, so nothing will change
|
||||
// beneath it
|
||||
@@ -158,6 +167,11 @@ class SpreaderManagerForTest : public ISpreaderManager {
|
||||
return &rv;
|
||||
}
|
||||
bool in_cache_warming_cycle() const override { return false; }
|
||||
bts::spark::ExecutionStrategy::SpreaderType
|
||||
get_spreader_quoting_type() const override {
|
||||
return bts::spark::ExecutionStrategy::SpreaderType::
|
||||
ExecutionStrategy_SpreaderType_REQUOTE;
|
||||
}
|
||||
|
||||
// SpreaderFractionalQtyHelper &fractional_qty_helper() {
|
||||
// return _fractional_qty_helper;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
syntax="proto3";
|
||||
|
||||
syntax="proto3";
|
||||
package bts.spark;
|
||||
option csharp_namespace="bts.spark";
|
||||
|
||||
@@ -39,9 +40,11 @@ message LegSpreaderParams
|
||||
}
|
||||
/// Legs can be quoted actively, or sent in reponse
|
||||
/// to fills
|
||||
bool is_active_quoting = 20;
|
||||
bool is_active_quoting = 20;
|
||||
bool enable_hedging = 30;
|
||||
QuoteParams quote_params = 40;
|
||||
ReverseHedgeQuoteParams reverse_hedge_quote_params = 43;
|
||||
SniperQuoteParams sniper_quote_params = 47;
|
||||
PreHedgeParams pre_hedge_params = 50;
|
||||
PostHedgeParams post_hedge_params = 60;
|
||||
MarketDataType market_data_type = 70;
|
||||
@@ -52,6 +55,8 @@ message LegSpreaderParams
|
||||
// ******************************************Quote**************************************************
|
||||
// *************************************************************************************************/
|
||||
|
||||
|
||||
|
||||
message QuoteParams
|
||||
{
|
||||
// Defines how much volume required to price off of a hedge leg level, as a ratio of working leg size.
|
||||
@@ -77,6 +82,16 @@ message QuoteParams
|
||||
NullableQuantity show_quantity = 2010;
|
||||
}
|
||||
|
||||
message ReverseHedgeQuoteParams{
|
||||
int32 n_ticks = 1;
|
||||
}
|
||||
|
||||
message SniperQuoteParams{
|
||||
int32 n_ticks = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************Quote MuteZone***********************************
|
||||
(TT Basic Slop)
|
||||
This rule sets a band above and below the quoting order inside of which any price changes will be
|
||||
@@ -476,6 +491,13 @@ message ExecutionStrategy
|
||||
RECALCULATE_CROSSES = 1;
|
||||
}
|
||||
HedgePricing hedge_pricing = 40;
|
||||
enum SpreaderType
|
||||
{
|
||||
REQUOTE = 0; // ie send out a quote leaning on the other legs and requotes
|
||||
REVERSE_HEDGE= 1; // sends an sniper IOC on one leg when the spread market is through the desired spread price
|
||||
SNIPER = 2; // sends simultanious cross orders on all legs when the spread market is through the desired spread price
|
||||
}
|
||||
SpreaderType spreader_type = 50;
|
||||
}
|
||||
|
||||
// obsolete in api, but still used internally by Spark csproj
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
SPARKD__CONFIG_DIR=src/server/sparkd/configurations/alphaworx_prod
|
||||
SPARKD__SHM_SIZE=8gb
|
||||
SPARKD__MEMORY=8gb
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/ubuntu/8000/sparkdata/conf/
|
||||
@@ -0,0 +1,4 @@
|
||||
SPARKD__CONFIG_DIR=src/server/sparkd/configurations/alphaworx_zen_hk_live
|
||||
SPARKD__SHM_SIZE=8gb
|
||||
SPARKD__MEMORY=8gb
|
||||
SPARKD__RUNTIME_CONF_DIR=/home/bts/8000/sparkdata/conf/
|
||||
@@ -0,0 +1,6 @@
|
||||
* Connects to Binance and Okx PRODUCTION sites for market data and execution
|
||||
* Api keys NOT included
|
||||
* Configured for Alphaworx
|
||||
|
||||
To retrieve api keys, run "python init_env.py". It should dump them to a file
|
||||
called ".env.local".
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"api_key": "${BINANCE_API_KEY}",
|
||||
"secret_key": "${BINANCE_SECRET_KEY}",
|
||||
"account": "PROD",
|
||||
"rest_endpoint": "https://api.binance.com",
|
||||
"ws_endpoint": "wss://ws-api.binance.com:443/ws-api/v3",
|
||||
"ws_stream_endpoint": "wss://stream.binance.com:9443",
|
||||
"use_cross_margin_api": true
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"api_key": "${BINANCE_API_KEY}",
|
||||
"secret_key": "${BINANCE_SECRET_KEY}",
|
||||
"account": "PROD",
|
||||
"rest_endpoint": "https://fapi.binance.com",
|
||||
"ws_endpoint": "wss://ws-fapi.binance.com/ws-fapi/v1",
|
||||
"ws_stream_endpoint": "wss://fstream.binance.com",
|
||||
"use_cross_margin_api": false
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import botocore
|
||||
import json
|
||||
import os
|
||||
|
||||
from boto3.session import Session
|
||||
from botocore.exceptions import ClientError
|
||||
from fileinput import FileInput
|
||||
|
||||
|
||||
def update_env_file(path, env_vars: dict):
|
||||
"""Update or add vars in a .env file in place."""
|
||||
if not os.path.exists(path):
|
||||
with open(path, "w") as file:
|
||||
for k, v in env_vars.items():
|
||||
file.write(f"{k}={v}\n")
|
||||
return
|
||||
|
||||
with FileInput(path, inplace=True) as file:
|
||||
for line in file:
|
||||
if not line.startswith("#"):
|
||||
stripped: str = line.lstrip()
|
||||
key_len = stripped.find("=")
|
||||
if key_len >= 0:
|
||||
k = stripped[0:key_len]
|
||||
if k in env_vars:
|
||||
print(f"{k}={env_vars[k]}")
|
||||
del env_vars[k]
|
||||
continue
|
||||
print(line, end="")
|
||||
|
||||
if len(env_vars) > 0:
|
||||
with open(path, "a") as file:
|
||||
for k, v in env_vars.items():
|
||||
file.write(f"{k}={v}\n")
|
||||
|
||||
|
||||
def get_secret():
|
||||
secret_name = "alphaworx-binance-api-keys"
|
||||
region_name = "ap-northeast-1"
|
||||
profile_name = "AdministratorAccess-849458505639"
|
||||
session = Session(profile_name=profile_name)
|
||||
client = session.client(
|
||||
service_name="secretsmanager",
|
||||
region_name=region_name,
|
||||
)
|
||||
|
||||
def on_token_error(e: Exception):
|
||||
print(f"""
|
||||
Failed to get secret value. {e}
|
||||
Verify you are logged in to aws, then try again.
|
||||
|
||||
aws sso login --profile {profile_name}
|
||||
|
||||
If this error persists, verify you have access to these api keys.
|
||||
For more help or information, talk to John.
|
||||
""")
|
||||
|
||||
try:
|
||||
get_secret_value_response = client.get_secret_value(
|
||||
SecretId=secret_name)
|
||||
except ClientError as e:
|
||||
print(f"Failed to get secret value.\n{e}")
|
||||
raise e
|
||||
except botocore.exceptions.SSOTokenLoadError as tl_err:
|
||||
on_token_error(tl_err)
|
||||
return None
|
||||
except botocore.exceptions.TokenRetrievalError as tr_err:
|
||||
on_token_error(tr_err)
|
||||
return None
|
||||
return get_secret_value_response["SecretString"]
|
||||
|
||||
|
||||
def _run():
|
||||
this_dir = os.path.dirname(__file__)
|
||||
secret_str = get_secret()
|
||||
if secret_str is None:
|
||||
exit(1)
|
||||
secret = json.loads(secret_str)
|
||||
env_vars = {}
|
||||
if "api-key" in secret:
|
||||
env_vars["BINANCE_API_KEY"] = secret["api-key"]
|
||||
if "secret-key" in secret:
|
||||
env_vars["BINANCE_SECRET_KEY"] = secret["secret-key"]
|
||||
update_env_file(f"{this_dir}/.env.local", env_vars)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_run()
|
||||
@@ -0,0 +1,124 @@
|
||||
QuickbusCfg {
|
||||
value {
|
||||
node {
|
||||
reconnect_period_secs: 1
|
||||
hb_period_msecs: 15000
|
||||
max_missed_hbs: 5
|
||||
parent_host: ""
|
||||
parent_port: 0
|
||||
my_port: 0
|
||||
}
|
||||
client {
|
||||
reconnect_period_secs: 1
|
||||
hb_period_msecs: 15000
|
||||
max_missed_hbs: 5
|
||||
parent_host: @SystemConfig.config_ip
|
||||
parent_port: @Ports.qbus_port
|
||||
my_port: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JetFIX {
|
||||
value {
|
||||
connection {
|
||||
name: "binance_1"
|
||||
venue: VENUE_BINANCE
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
connection {
|
||||
name: "binance_usds_futures_1"
|
||||
venue: VENUE_BINANCE_USDS_FUTURES
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
connection {
|
||||
name: "okx_1"
|
||||
venue: VENUE_OKX
|
||||
max_order_msgs_per_window: 300
|
||||
window_duration_msecs: 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MarketDataConfig {
|
||||
value {
|
||||
binance {
|
||||
num_depth_levels: 5
|
||||
url_rest_base: "https://api.binance.com"
|
||||
url_ws_base: "wss://stream.binance.com:9443"
|
||||
security_criteria {
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_SPOT
|
||||
symbols: @SymbolLists.list[Binance].symbol
|
||||
name_regexps: "USDC|USDT$"
|
||||
}
|
||||
}
|
||||
}
|
||||
binance_usds_futures {
|
||||
num_depth_levels: 5
|
||||
url_rest_base: "https://fapi.binance.com"
|
||||
url_ws_base: "wss://fstream.binance.com"
|
||||
security_criteria {
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_FUTURE
|
||||
symbols: @SymbolLists.list[BinanceUsdsFutures].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
okx {
|
||||
num_depth_levels: 5
|
||||
url_rest_base: "https://aws.okx.com"
|
||||
url_ws_base: "wss://wsaws.okx.com:8443"
|
||||
security_criteria {
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_SPOT
|
||||
symbols: @SymbolLists.list[OkxSpots].symbol
|
||||
}
|
||||
clauses {
|
||||
security_types: SECURITY_TYPE_FUTURE
|
||||
symbols: @SymbolLists.list[OkxFutures].symbol
|
||||
}
|
||||
}
|
||||
is_application_ping_pong_enabled: true
|
||||
application_ping_interval_ms: 20000
|
||||
application_pong_timeout_ms: 10000
|
||||
is_protocol_ping_pong_enabled: true
|
||||
protocol_ping_interval_ms: 60000
|
||||
protocol_pong_timeout_ms: 30000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NotSimExecution {
|
||||
value {
|
||||
entries {
|
||||
venue: VENUE_BINANCE
|
||||
}
|
||||
entries {
|
||||
venue: VENUE_BINANCE_USDS_FUTURES
|
||||
}
|
||||
entries {
|
||||
venue: VENUE_OKX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OkxExeCfg {
|
||||
value {
|
||||
account: "PROD"
|
||||
ops_id: "op_id_bts"
|
||||
secret_key: "240038D7A28D7F9461247CFCB8E43710"
|
||||
api_key: "dc188532-c74c-4d40-affe-3c6bf4d0ca9a"
|
||||
passphrase: ":,7i%tA%ivfj%SCbX?Ut"
|
||||
ws_url: "wss://wsaws.okx.com:8443"
|
||||
rest_url: "https://www.okx.com"
|
||||
ws_ping_timeout_seconds: 10
|
||||
ws_ping_interval_seconds: 25
|
||||
ws_reconnect_interval_seconds: 5
|
||||
ws_reconnect_max_count: 5
|
||||
simulated_trading: false
|
||||
tdmode: "cross"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
SymbolLists {
|
||||
value {
|
||||
list {
|
||||
key: "Binance"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "PAXG"
|
||||
symbol: "PEPE"
|
||||
symbol: "S"
|
||||
symbol: "SHIB"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TAO"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "XRP"
|
||||
}
|
||||
list {
|
||||
key: "BinanceUsdsFutures"
|
||||
symbol: "1000PEPE"
|
||||
symbol: "1000SHIB"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "S"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TAO"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "XRP"
|
||||
}
|
||||
list {
|
||||
key: "OkxSpots"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BETH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "PEPE"
|
||||
symbol: "S"
|
||||
symbol: "SHIB"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "USDT"
|
||||
symbol: "XRP"
|
||||
}
|
||||
list {
|
||||
key: "OkxFutures"
|
||||
symbol: "ADA"
|
||||
symbol: "APT"
|
||||
symbol: "AVAX"
|
||||
symbol: "BCH"
|
||||
symbol: "BNB"
|
||||
symbol: "BTC"
|
||||
symbol: "DOGE"
|
||||
symbol: "DOT"
|
||||
symbol: "ETH"
|
||||
symbol: "HBAR"
|
||||
symbol: "LINK"
|
||||
symbol: "LTC"
|
||||
symbol: "OM"
|
||||
symbol: "PEPE"
|
||||
symbol: "S"
|
||||
symbol: "SHIB"
|
||||
symbol: "SOL"
|
||||
symbol: "SUI"
|
||||
symbol: "TAO"
|
||||
symbol: "TRUMP"
|
||||
symbol: "USDC"
|
||||
symbol: "XRP"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Symbols {
|
||||
value {
|
||||
venues {
|
||||
name: "VENUE_BINANCE"
|
||||
spot: @SymbolLists.list[Binance].symbol
|
||||
}
|
||||
venues {
|
||||
name: "VENUE_BINANCE_USDS_FUTURES"
|
||||
future: @SymbolLists.list[BinanceUsdsFutures].symbol
|
||||
}
|
||||
venues {
|
||||
name: "VENUE_OKX"
|
||||
spot: @SymbolLists.list[OkxSpots].symbol
|
||||
future: @SymbolLists.list[OkxFutures].symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -47,7 +47,7 @@ def _get_arg_parser():
|
||||
)
|
||||
# TODO: add more services (api-server, pubsub, dsqa web server, etc.)
|
||||
all_services = ["sparkd"]
|
||||
parser.add_argument("services", nargs="*")
|
||||
parser.add_argument("services", help="this selects services defined in compose.yaml", nargs="*")
|
||||
parser.set_defaults(
|
||||
configuration="release",
|
||||
services=all_services,
|
||||
@@ -70,7 +70,7 @@ def _get_env_files(services, profile):
|
||||
add(root.joinpath(".env"))
|
||||
add(root.joinpath(".env.local"))
|
||||
if profile is not None:
|
||||
if "sparkd" in services:
|
||||
if "sparkd" in services or "sparkd-symbols" in services:
|
||||
profile_dir=root.joinpath("src/server/sparkd/configurations", profile)
|
||||
add(profile_dir.joinpath(".env"))
|
||||
add(profile_dir.joinpath(".env.local"))
|
||||
|
||||
Reference in new issue
Block a user