Compare commits

..
2 Commits
19 changed files with 66 additions and 81 deletions

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 less than the threshold defined.  The hedge order is
hedge price is more 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
@@ -227,7 +227,7 @@ namespace mbts.ui.spark {
}
DataGridColumn _column_factory(LegSpreaderParamsTuple l) {
var col = new DataGridColumnInternal(l.leg.Security, ParameterCellTemplateConverter, ParameterCellEditingTemplateConverter);
var col = new DataGridColumnInternal(l.leg.Security, ParameterCellTemplateConverter, ParameterCellEditingTemplateConverter) { Width = 75, };
col.HeaderTemplate = (DataTemplate)FindResource(IsNew ? RemovableColumnHeaderTemplateKey : NonRemovableColumnHeaderTemplateKey);
DataGridEx.SetRightBorder(col, new DataGridExVerticalLine(false, true, Colors.DarkGray, 1));
return col;
@@ -501,12 +501,6 @@ 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 = 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);
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);
}
var nd = new PNLNormalizedData(
DoubleUtil.round_to_decimal(day_pnl.value),
(decimal)DoubleUtil.nan_to_zero(day_pnl.value),
day_long,
day_short,
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),
(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),
sod_long,
sod_short,
DoubleUtil.round_to_decimal(data.working_long_pos),
DoubleUtil.round_to_decimal(data.working_short_pos));
(decimal)DoubleUtil.nan_to_zero(data.working_long_pos),
(decimal)DoubleUtil.nan_to_zero(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(true),
_calculation_type.observe_current(),
(data, calc) => data.with(calc_type: calc)
).FilterWithRaw(filter_src, PNLRowData.key_fn, null)
.OnDispatcher()
+2
View File
@@ -75,6 +75,7 @@ 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(
@@ -264,6 +265,7 @@ 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,9 +1,10 @@
using System;
using System.Linq;
namespace mbts.ui.controls {
static class DoubleUtil {
public const int API_DECIMAL_PRECISION = 9;
namespace mbts.ui.controls
{
internal class DoubleUtil
{
/* smallest such that 1.0+DBL_EPSILON != 1.0 */
private const double EPSILON = 2.2204460492503131e-016;
private const double BIG_EPSILON = EPSILON * 10;
@@ -35,9 +36,6 @@ 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);
+45 -54
View File
@@ -8,6 +8,7 @@ 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 {
@@ -93,38 +94,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 added = this.added as KeyedValueSet<TKey, T> ?? new KeyedValueSet<TKey, T>(this.added, _key);
var comp = new RowEqualityComparer<T, TKey>(_key);
var added = this.added as HashSet<T> ?? new HashSet<T>(this.added, comp);
var changes = this.changed as ChangeDict<T,TKey> ?? new ChangeDict<T,TKey>(this.changes, _key);
var removed = this.removed as KeyedValueSet<TKey, T> ?? new KeyedValueSet<TKey, T>(this.removed, _key);
var removed = this.removed as HashSet<T> ?? new HashSet<T>(this.removed, comp);
// Add
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;
}
}
added.UnionWith(next.added);
// Change
foreach (var c in next.changes) {
var k = _key(c.Old);
if (!added.Replace(k, c.New))
if (added.Contains(c.Old)) {
added.Remove(c.Old);
added.Add(c.New);
}
else {
changes.AddOrMerge(c);
}
}
// Remove
foreach (var r in next.removed) {
var k = _key(r);
if (!added.Remove(k))
removed[k] = changes.TryRemove(k, out var ch) ? ch.Old : r;
if (!added.Remove(r)) {
removed.Add(r);
}
changes.Remove(_key(r));
}
return new Update<T, TKey>(
next.all,
added, changes, removed,
_key);
_key
);
}
public IEnumerable<T> all { get; }
@@ -147,39 +148,6 @@ 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;
@@ -199,11 +167,9 @@ namespace bts.api.core {
return null;
}
public bool Remove(TKey key) =>
public void 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() {
@@ -215,6 +181,31 @@ 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);
@@ -931,4 +922,4 @@ namespace bts.api.core {
$"T is '{typeof(T)}', TKey is '{typeof(TKey)}'";
}
}
}
}
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.