Compare commits

...
Author SHA1 Message Date
Taha Afzal 66ad51280f Reversehedging fixed 2025-04-08 22:13:33 +00:00
arham 029edd8a86 Format: ran clang format on file 2025-04-07 15:39:57 +00:00
arham dfdcbab2a0 Add: config changes to make server controller work and set up hk zen server 2025-04-07 15:33:26 +00:00
Taha Afzal 6d7c0702f0 Fixing build: 2025-04-05 23:38:05 +00:00
Taha Afzal 86eaddea93 Fixing a bug, where the spreader was isidentifying the quoting leg 2025-04-05 15:38:30 +00:00
John Colvin 57f8f3ff58 ui: Add Sniper and Reverse Hedge controls 2025-04-04 00:19:38 -04:00
John Colvin 775df2850d Add Sniper and Reverse Hedge params to spreader proto 2025-04-04 00:19:38 -04:00
Taha Afzal cb2b15f10b Adding IOC to SimExecution 2025-04-03 23:24:30 +00:00
Taha Afzal 60362a4c95 Adding reverse-hedge to spreader 2025-04-03 23:24:30 +00:00
John Colvin c6d7a8f38c ui (pnl): Use dark theme fg in "Selected" and "Total" labels
Previously, it was black and hard to read since the background is dark.
2025-03-26 14:46:44 -04:00
John Colvin 7931c62b46 ui (pnl): Hide "Override Cpp" menu item
The overrides aren't respected in (new) pnl calcs.
2025-03-26 14:35:23 -04:00
John Colvin 58518451c8 ui (pnl): Show realized/unrealized pnl in row group totals 2025-03-26 14:31:04 -04:00
51 changed files with 1229 additions and 152 deletions

No files matched your search

+1
View File
@@ -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
+1 -1
View File
@@ -326,4 +326,4 @@
"description": "Test to run",
},
]
}
}
+37
View File
@@ -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);
}
}
@@ -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);
}
}
}
@@ -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.
+2 -1
View File
@@ -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 ////////////////////////////////
////////////////////////////////////////////////////
@@ -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();
@@ -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;
+24 -2
View File
@@ -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
}
@@ -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
View File
@@ -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"))