Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da42e95754 | ||
|
|
a878a55ac1 | ||
|
|
4305d560aa | ||
|
|
055f0015e7 | ||
|
|
ddc50e1fba | ||
|
|
ffb571d1cf | ||
|
|
2a36c05d75 | ||
|
|
a3730eb203 | ||
|
|
d033275694 | ||
|
|
016ddf9b69 | ||
|
|
0cc5817932 |
No files matched your search
@@ -154,7 +154,7 @@ insert_anchor_links = "right"
|
||||
|
||||
- Pay Less - If enabled by checking the checkbox, the spreader will
|
||||
attempt to pay less when the quantity at the level of the calculated
|
||||
hedge price is more than the threshold defined. The hedge order is
|
||||
hedge price is less than the threshold defined. The hedge order is
|
||||
paid less by the “Payless Ticks” as defined per leg.
|
||||
- Pay Up - If enabled by checking the checkbox, the spreader will pay
|
||||
up when the quantity at the level of the calculated hedge price is
|
||||
|
||||
+1
-1
Submodule docker/linux updated: e13bb5d8df...c40e6eba4b.
+1
-1
Submodule externals updated: b5ca264286...6d8f64ca5c.
@@ -227,7 +227,7 @@ namespace mbts.ui.spark {
|
||||
}
|
||||
|
||||
DataGridColumn _column_factory(LegSpreaderParamsTuple l) {
|
||||
var col = new DataGridColumnInternal(l.leg.Security, ParameterCellTemplateConverter, ParameterCellEditingTemplateConverter) { Width = 75, };
|
||||
var col = new DataGridColumnInternal(l.leg.Security, ParameterCellTemplateConverter, ParameterCellEditingTemplateConverter);
|
||||
col.HeaderTemplate = (DataTemplate)FindResource(IsNew ? RemovableColumnHeaderTemplateKey : NonRemovableColumnHeaderTemplateKey);
|
||||
DataGridEx.SetRightBorder(col, new DataGridExVerticalLine(false, true, Colors.DarkGray, 1));
|
||||
return col;
|
||||
|
||||
@@ -501,6 +501,12 @@ namespace bts.shell.pnl {
|
||||
account_name == other.account_name &&
|
||||
sod == other.sod &&
|
||||
day == other.day &&
|
||||
bid_price.Equals(other.bid_price) &&
|
||||
ask_price.Equals(other.ask_price) &&
|
||||
last_price.Equals(other.last_price) &&
|
||||
mid_price.Equals(other.mid_price) &&
|
||||
settlement_price.Equals(other.settlement_price) &&
|
||||
calc_type.Equals(other.calc_type) &&
|
||||
raw_day == other.raw_day &&
|
||||
working.summary == other.working.summary;
|
||||
|
||||
|
||||
@@ -97,22 +97,22 @@ namespace bts.shell.pnl {
|
||||
if (security.HasValue && security.Value.ContractCase != Security.ContractOneofCase.Future) {
|
||||
day_long = day_short = sod_long = sod_short = 0;
|
||||
} else {
|
||||
day_long = (decimal)DoubleUtil.nan_to_zero(data.day.long_pos);
|
||||
day_short = (decimal)DoubleUtil.nan_to_zero(data.day.short_pos);
|
||||
sod_long = (decimal)DoubleUtil.nan_to_zero(data.sod.long_pos);
|
||||
sod_short = (decimal)DoubleUtil.nan_to_zero(data.sod.short_pos);
|
||||
day_long = DoubleUtil.round_to_decimal(data.day.long_pos);
|
||||
day_short = DoubleUtil.round_to_decimal(data.day.short_pos);
|
||||
sod_long = DoubleUtil.round_to_decimal(data.sod.long_pos);
|
||||
sod_short = DoubleUtil.round_to_decimal(data.sod.short_pos);
|
||||
}
|
||||
var nd = new PNLNormalizedData(
|
||||
(decimal)DoubleUtil.nan_to_zero(day_pnl.value),
|
||||
DoubleUtil.round_to_decimal(day_pnl.value),
|
||||
day_long,
|
||||
day_short,
|
||||
(decimal)DoubleUtil.nan_to_zero(data.raw_day.long_pos),
|
||||
(decimal)DoubleUtil.nan_to_zero(data.raw_day.short_pos),
|
||||
(decimal)DoubleUtil.nan_to_zero(sod_pnl.value),
|
||||
DoubleUtil.round_to_decimal(data.raw_day.long_pos),
|
||||
DoubleUtil.round_to_decimal(data.raw_day.short_pos),
|
||||
DoubleUtil.round_to_decimal(sod_pnl.value),
|
||||
sod_long,
|
||||
sod_short,
|
||||
(decimal)DoubleUtil.nan_to_zero(data.working_long_pos),
|
||||
(decimal)DoubleUtil.nan_to_zero(data.working_short_pos));
|
||||
DoubleUtil.round_to_decimal(data.working_long_pos),
|
||||
DoubleUtil.round_to_decimal(data.working_short_pos));
|
||||
if (_normalized_data != nd) {
|
||||
_normalized_data = nd;
|
||||
updated?.Invoke(nd);
|
||||
|
||||
@@ -103,7 +103,7 @@ namespace bts.shell.pnl {
|
||||
load_from(settings);
|
||||
_dispose = Disposable.Create(
|
||||
pnl_source.Operate(
|
||||
_calculation_type.observe_current(),
|
||||
_calculation_type.observe_current(true),
|
||||
(data, calc) => data.with(calc_type: calc)
|
||||
).FilterWithRaw(filter_src, PNLRowData.key_fn, null)
|
||||
.OnDispatcher()
|
||||
|
||||
@@ -75,7 +75,6 @@ namespace mbts.spark {
|
||||
.TableCheckedAutoCorrect(EqualityComparer<(SecurityImmutable? sec, PNLUnitImmutable data)>.Default)
|
||||
.Where(t => t.has_changes())
|
||||
.Cache();
|
||||
on_account_pnl = _position_service.subscribei_pnl_account_data().Naggle(interval, scheduler).Table().Cache();
|
||||
var working_orders = on_orders.Filter(tup => tup.order.is_active());
|
||||
this.working_orders =
|
||||
on_orders.Scan(
|
||||
@@ -265,7 +264,6 @@ namespace mbts.spark {
|
||||
public IObservable<IReadOnlyDictionary<uint, OrderSecurity>> working_orders { get; }
|
||||
public IObservable<TableUpdate<(SecurityImmutable?, PNLUnitImmutable), int>> on_pnl { get; }
|
||||
public IObservable<TableUpdate<PNLRowData, PNLKey>> security_account_pnl { get; }
|
||||
public IObservable<TableUpdate<AccountPNLImmutable, uint>> on_account_pnl { get; }
|
||||
public IObservable<TableUpdate<(SecurityImmutable?, PositionUnitImmutable), int>> on_positions { get; }
|
||||
public IObservable<TableUpdate<(AlgoData algo, AlgoDefinitionMetadata? meta), AlgoKey>> studio_algos_with_meta { get; }
|
||||
public IObservable<TableUpdate<(SecurityImmutable?, ManualFillImmutable), int>> on_manual_fills_securities { get; }
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace mbts.ui.controls
|
||||
{
|
||||
internal class DoubleUtil
|
||||
{
|
||||
namespace mbts.ui.controls {
|
||||
static class DoubleUtil {
|
||||
public const int API_DECIMAL_PRECISION = 9;
|
||||
/* smallest such that 1.0+DBL_EPSILON != 1.0 */
|
||||
private const double EPSILON = 2.2204460492503131e-016;
|
||||
private const double BIG_EPSILON = EPSILON * 10;
|
||||
@@ -36,6 +35,9 @@ namespace mbts.ui.controls
|
||||
(double.IsNaN(right) ? double.NaN : -right) :
|
||||
(double.IsNaN(right) ? left : left - right);
|
||||
|
||||
public static decimal round_to_decimal(double value, int decimals = API_DECIMAL_PRECISION) =>
|
||||
double.IsNaN(value) ? 0 : (decimal)Math.Round(value, decimals, MidpointRounding.AwayFromZero);
|
||||
|
||||
internal static bool AreClose(double v1, double v2) {
|
||||
if (v1 == v2) return true;
|
||||
double delta = Math.Abs(v1 - v2);
|
||||
|
||||
@@ -8,7 +8,6 @@ using System.Linq;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
|
||||
namespace bts.api.core {
|
||||
@@ -94,38 +93,38 @@ namespace bts.api.core {
|
||||
new Update<T, TKey>(new T[0], new T[0], new Change<T>[0], new T[0], key_extractor);
|
||||
|
||||
public Update<T,TKey> merge(Update<T, TKey> next) {
|
||||
var comp = new RowEqualityComparer<T, TKey>(_key);
|
||||
var added = this.added as HashSet<T> ?? new HashSet<T>(this.added, comp);
|
||||
var added = this.added as KeyedValueSet<TKey, T> ?? new KeyedValueSet<TKey, T>(this.added, _key);
|
||||
var changes = this.changed as ChangeDict<T,TKey> ?? new ChangeDict<T,TKey>(this.changes, _key);
|
||||
var removed = this.removed as HashSet<T> ?? new HashSet<T>(this.removed, comp);
|
||||
var removed = this.removed as KeyedValueSet<TKey, T> ?? new KeyedValueSet<TKey, T>(this.removed, _key);
|
||||
|
||||
// Add
|
||||
added.UnionWith(next.added);
|
||||
foreach (var v in next.added) {
|
||||
var k = _key(v);
|
||||
if (removed.Remove(k, out var oldval)) {
|
||||
changes.AddOrMerge(new Change<T>(oldval, v));
|
||||
} else {
|
||||
added[k] = v;
|
||||
}
|
||||
}
|
||||
|
||||
// Change
|
||||
foreach (var c in next.changes) {
|
||||
if (added.Contains(c.Old)) {
|
||||
added.Remove(c.Old);
|
||||
added.Add(c.New);
|
||||
}
|
||||
else {
|
||||
var k = _key(c.Old);
|
||||
if (!added.Replace(k, c.New))
|
||||
changes.AddOrMerge(c);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove
|
||||
foreach (var r in next.removed) {
|
||||
if (!added.Remove(r)) {
|
||||
removed.Add(r);
|
||||
}
|
||||
changes.Remove(_key(r));
|
||||
var k = _key(r);
|
||||
if (!added.Remove(k))
|
||||
removed[k] = changes.TryRemove(k, out var ch) ? ch.Old : r;
|
||||
}
|
||||
|
||||
return new Update<T, TKey>(
|
||||
next.all,
|
||||
added, changes, removed,
|
||||
_key
|
||||
);
|
||||
_key);
|
||||
}
|
||||
|
||||
public IEnumerable<T> all { get; }
|
||||
@@ -148,6 +147,39 @@ namespace bts.api.core {
|
||||
#endif
|
||||
}
|
||||
|
||||
class KeyedValueSet<TKey, TValue> : IEnumerable<TValue> {
|
||||
readonly Dictionary<TKey, TValue> _cache = new Dictionary<TKey, TValue>();
|
||||
|
||||
public KeyedValueSet(IEnumerable<TValue> value, Func<TValue, TKey> key) {
|
||||
foreach (var v in value)
|
||||
_cache[key(v)] = v;
|
||||
}
|
||||
|
||||
public TValue this[TKey key] {
|
||||
set => _cache[key] = value;
|
||||
}
|
||||
|
||||
public bool Remove(TKey key) =>
|
||||
_cache.Remove(key);
|
||||
|
||||
public bool Remove(TKey key, out TValue value) =>
|
||||
_cache.TryGetValue(key, out value) && _cache.Remove(key);
|
||||
|
||||
public bool Replace(TKey key, TValue value) {
|
||||
if (_cache.ContainsKey(key)) {
|
||||
_cache[key] = value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public IEnumerator<TValue> GetEnumerator() =>
|
||||
_cache.Values.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() =>
|
||||
GetEnumerator();
|
||||
}
|
||||
|
||||
class ChangeDict<T, TKey> : IEnumerable<Change<T>> {
|
||||
Dictionary<TKey, Change<T>> _changes;
|
||||
Func<Change<T>, TKey> _key;
|
||||
@@ -167,9 +199,11 @@ namespace bts.api.core {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Remove(TKey key) {
|
||||
public bool Remove(TKey key) =>
|
||||
_changes.Remove(key);
|
||||
}
|
||||
|
||||
public bool TryRemove(TKey key, out Change<T> result) =>
|
||||
_changes.TryGetValue(key, out result) && _changes.Remove(key);
|
||||
|
||||
#region IEnumerable
|
||||
public IEnumerator<Change<T>> GetEnumerator() {
|
||||
@@ -181,31 +215,6 @@ namespace bts.api.core {
|
||||
#endregion
|
||||
}
|
||||
|
||||
struct RowEqualityComparer<T,TKey> : IEqualityComparer<T>, IEqualityComparer<Change<T>>
|
||||
where TKey : IEquatable<TKey> {
|
||||
readonly Func<T,TKey> _key;
|
||||
|
||||
public RowEqualityComparer(Func<T,TKey> key) {
|
||||
_key = key;
|
||||
}
|
||||
|
||||
public bool Equals(T x, T y) {
|
||||
return _key(x).Equals(_key(y));
|
||||
}
|
||||
|
||||
public bool Equals(Change<T> x, Change<T> y) {
|
||||
return Equals(x.New, y.New);
|
||||
}
|
||||
|
||||
public int GetHashCode(T obj) {
|
||||
return _key(obj).GetHashCode();
|
||||
}
|
||||
|
||||
public int GetHashCode(Change<T> c) {
|
||||
return GetHashCode(c.New);
|
||||
}
|
||||
}
|
||||
|
||||
public class TableUpdate<T, TKey> where TKey : IEquatable<TKey> {
|
||||
// warning: this does not have a key_extractor
|
||||
public static readonly TableUpdate<T, TKey> empty = new TableUpdate<T, TKey>(ImmutableDictionary<TKey, T>.Empty, Array.Empty<T>(), Array.Empty<Change<T>>(), Array.Empty<T>(), null);
|
||||
@@ -922,4 +931,4 @@ namespace bts.api.core {
|
||||
$"T is '{typeof(T)}', TKey is '{typeof(TKey)}'";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user