public static void CheckMaximalRoundOffError(bool isSizeBased, InstrumentSize size, Money amount, Price price, Money accruedInterest, Side side) { if (!isSizeBased) { InstrumentSize calcAmt = size.CalculateAmount(price) * (decimal)side * -1M; //if (accruedInterest != null && accruedInterest.IsNotZero) //{ // accruedInterest = accruedInterest.Abs() * (decimal)side * -1M; // calcAmt += accruedInterest; //} InstrumentSize diff = (calcAmt.Abs() - amount.Abs()); if (diff.IsNotZero && !diff.IsWithinTolerance(0.02m)) { decimal percLeft = diff.Abs().Quantity / amount.Abs().Quantity; if (percLeft >= 0.05m) throw new ApplicationException(string.Format( "Price times Size ({0}) differs by {1}% from the provided Amount ({2}). Order cannot be filled.", calcAmt.DisplayString, Math.Round(percLeft * 100m, 1), amount.DisplayString)); } } }
protected virtual TransactionFillDetails getTransactionFillDetailsAmountBasedOrderByGoalSeek( Money grossAmount, Side side, bool isCommissionRelevant, bool isValueInclComm, DateTime settlementDate, Price price, IExchange exchange, ICommRule rule, ICommClient client, decimal servChargePerc, int precision) { decimal realAmount; decimal guess = grossAmount.Abs().CalculateSize(price).Quantity; FinancialMath.MaxCycles = 200; // Check -> use Commission bool useComm = true; bool useAddComm = false; if (!isCommissionRelevant || rule == null) useComm = false; if (useComm) useAddComm = (rule.AdditionalCalculation != null); realAmount = FinancialMath.GoalSeek(x => new InstrumentSize(x, this).CalculateAmount(price).Quantity + (useComm ? rule.CommCalculation.Calculate(client.GetNewInstance(new InstrumentSize(x, this), price, (useAddComm ? rule.AdditionalCalculation.Calculate(client.GetNewInstance(new InstrumentSize(x, this), price)) : null))).Quantity : 0M) + (useAddComm ? rule.AdditionalCalculation.Calculate(client.GetNewInstance(new InstrumentSize(x, this), price)).Quantity : 0M) + (new InstrumentSize(x, this).CalculateAmount(price).Abs().Quantity * servChargePerc), grossAmount.Abs().Quantity, guess, precision); InstrumentSize size = new InstrumentSize(realAmount, this); Money amount = size.CalculateAmount(price); InstrumentSize cleanSize = amount.CalculateSize(price); Money servCh = (amount.Abs() * servChargePerc); Money comm = amount.ZeroedAmount(); Money addComm = amount.ZeroedAmount(); if (useComm) { if (rule.AdditionalCalculation != null) addComm = rule.AdditionalCalculation.Calculate(client.GetNewInstance(cleanSize, price)); comm = rule.CommCalculation.Calculate(client.GetNewInstance(cleanSize, price, addComm)); // if sell -> comm is already in the amount if (side == Side.Sell && (comm + addComm) != null && (comm + addComm).IsNotZero) { amount += (comm + addComm); cleanSize = amount.CalculateSize(price); if (!isValueInclComm) { if (rule.AdditionalCalculation != null) addComm = rule.AdditionalCalculation.Calculate(client.GetNewInstance(cleanSize, price)); comm = rule.CommCalculation.Calculate(client.GetNewInstance(cleanSize, price, addComm)); } } } return new TransactionFillDetails(cleanSize, amount, null, servCh, servChargePerc, comm + addComm, grossAmount.Abs(), side); }
/// <summary> /// Calculate the amount using a size /// </summary> /// <param name="size"></param> /// <returns></returns> public Money CalculateAmount(InstrumentSize size) { return size.CalculateAmount(this, false); }
/// <summary> /// This method gives back the weighted average of two size & price pairs /// </summary> /// <param name="price1">The first instance of the <see cref="T:B4F.TotalGiro.Instruments.Price">Price</see> class</param> /// <param name="size1">The first instance of the <see cref="T:B4F.TotalGiro.Instruments.InstrumentSize">InstrumentSize</see> class</param> /// <param name="price2">The second instance of the <see cref="T:B4F.TotalGiro.Instruments.Price">Price</see> class</param> /// <param name="size2">The second instance of the <see cref="T:B4F.TotalGiro.Instruments.InstrumentSize">InstrumentSize</see> class</param> /// <returns>A new instance of the <see cref="T:B4F.TotalGiro.Instruments.Price">Price</see> class with the weighted price</returns> public static Price GetAveragePrice(Price price1, InstrumentSize size1, Price price2, InstrumentSize size2) { if (price1 == null && size1 == null && price2 == null && size2 == null) { return null; } if (price1 == null || size1 == null) { return price2; } if (price2 == null || size2 == null) { return price1; } if (price1.Underlying != price2.Underlying) { throw new ApplicationException("Both prices have to be in the same currency"); } if (price1.Instrument != price2.Instrument) { throw new ApplicationException("Both prices have to be for the same Instrument"); } if (size1.Underlying != size2.Underlying) { throw new ApplicationException("Both amounts/sizes have to be in the same instrument"); } if (price1.Instrument != size1.Underlying) { throw new ApplicationException("The price and the size have to be for the same Instrument"); } Money total = size1.CalculateAmount(price1) + size2.CalculateAmount(price2); return total / (size1 + size2); }
public static void PriceChanged(OrderFillView orderFillView) { IDalSession session = NHSessionFactory.CreateSession(); try { Price price; InstrumentSize size; Money amount; ITradeableInstrument tradedInstrument; IOrder order = OrderMapper.GetOrder(session, orderFillView.OrderId); if (!orderFillView.IsSizeBased) { // Exchange rate (in base currency) tradedInstrument = ((IOrderAmountBased)order).TradedInstrument; price = new Price(orderFillView.Price, tradedInstrument.CurrencyNominal, tradedInstrument); amount = new Money(orderFillView.Amount, (ICurrency)order.Value.Underlying); if (tradedInstrument.CurrencyNominal.Key != amount.Underlying.Key) { if (!(tradedInstrument.CurrencyNominal.IsObsoleteCurrency && tradedInstrument.CurrencyNominal.ParentInstrument.Key == amount.Underlying.Key)) throw new ApplicationException("It is not possible to fill an order in a different currency."); } size = amount.CalculateSize(price); orderFillView.Size = size.Quantity; } else { tradedInstrument = ((IOrderSizeBased)order).TradedInstrument; price = new Price(orderFillView.Price, tradedInstrument.CurrencyNominal, tradedInstrument); size = new InstrumentSize(orderFillView.Size, tradedInstrument); amount = size.CalculateAmount(price); amount.XRate = orderFillView.ExchangeRate; orderFillView.Amount = amount.Quantity; } // Check if the Price is still reliable IPriceDetail lastValidHistoricalPrice = HistoricalPriceMapper.GetLastValidHistoricalPrice( session, tradedInstrument, orderFillView.TransactionDate); if (lastValidHistoricalPrice == null || lastValidHistoricalPrice.Price.IsZero) orderFillView.Warning = string.Format("No price was found for {0:d}, so validation is not very reliable.", orderFillView.TransactionDate); else { // check if the price is within 1% of the last historical price decimal rate = lastValidHistoricalPrice.Price.Quantity; decimal diff = (price.Quantity - rate) / rate; decimal diffPct = Math.Round(Math.Abs(diff), 4) * 100; if (diffPct > 1) orderFillView.Warning = string.Format("The price entered is {0:0.##}% {1} than the last known price for {2:d} ({3}).", diffPct, (diff < 0 ? "lower" : "higher"), orderFillView.TransactionDate, lastValidHistoricalPrice.Price.ShortDisplayString); if (lastValidHistoricalPrice.WasOldDateBy(orderFillView.TransactionDate)) orderFillView.Warning += (orderFillView.Warning != string.Empty ? "\n" : "") + string.Format("The last known price for {0:d} is {1} days old (last updated on {2:d}), so validation is not very reliable.", orderFillView.TransactionDate, (orderFillView.TransactionDate - lastValidHistoricalPrice.Date).Days, lastValidHistoricalPrice.Date); } } finally { session.Close(); } }
public ICommClient GetNewInstance(InstrumentSize size, Price price, Money previousCalculatedFee) { this.Value = size; this.Price = price; this.PreviousCalculatedFee = previousCalculatedFee; this.GrossAmount = size.CalculateAmount(price); this.amountIsNett = true; return this; }
protected void calculateBookStuff(IFundPositionTx posTx, IsOpenClose isOpen, InstrumentSize newSize, Money realisedAmount, Money baseRealisedAmount) { // Book Value & AvgOpenExRate if (isOpen == IsOpenClose.Close) { if (!posTx.DoNotRealize) { Money oldBookValue = BookValue; Money oldBookValueIC = BookValueIC; if (Size.IsNotZero && newSize.IsNotZero) { BookValueIC = Money.Add(Money.Add(BookValueIC, posTx.BookValueIC, true), realisedAmount, true); if (newSize.IsZero && BookValueIC.IsNotZero) BookValueIC = BookValueIC.ZeroedAmount(); //BookValue = Money.Add(Money.Add(BookValue, posTx.BookValue, true), baseRealisedAmount, true); BookValue = Money.Add(BookValue, posTx.Size.CalculateAmount(this.BookPrice), true); if (newSize.IsZero && BookValue.IsNotZero) BookValue = BookValue.ZeroedAmount(); } else { BookValueIC = BookValueIC.Clone(0M); BookValue = BookValue.Clone(0M); } BookChange = Money.Add(BookChange, Money.Subtract(BookValue, oldBookValue, true), true); BookChangeIC = Money.Add(BookChangeIC, Money.Subtract(BookValueIC, oldBookValueIC, true), true); } else { BookChange = BookValue.Clone(0M); BookChangeIC = BookValueIC.Clone(0M); } } else if (isOpen == IsOpenClose.Open) { Money bookChange = posTx.BookValue; BookChange = Money.Add(BookChange, bookChange, true); BookValue = Money.Add(BookValue, bookChange, true); Money bookChangeIC = posTx.BookValueIC; BookChangeIC = Money.Add(BookChangeIC, bookChangeIC, true); BookValueIC = Money.Add(BookValueIC, bookChangeIC, true); if (newSize.IsNotZero) { BookPrice = Money.Divide(BookValue, newSize, true); if (Size != null) { // for a conversion the avg ExRate does not change if (!posTx.IsConversion) { if (!InstrumentCurrency.IsBase) { Money currentCostAmount = Size.CalculateAmount(CostPrice, true); Money totalAmtIC = Money.Add(currentCostAmount, posTx.BookValueIC, true); //Money totalAmt = Money.Add(Money.Convert(Money.Multiply(Size, CostPrice, true), (1M / AvgOpenExRate), InstrumentCurrency.BaseCurrency, true), posTx.BookValue, true); Money totalAmt = Money.Add(currentCostAmount.ConvertToBase((1M / AvgOpenExRate), true), posTx.BookValue, true); AvgOpenExRate = totalAmtIC.Quantity / totalAmt.Quantity; } else AvgOpenExRate = 1M; } } else AvgOpenExRate = posTx.ExchangeRate; } } else // IsOpenClose.Both { // if swap -> take the price from the Tx if (posTx.Price.Underlying.IsBase) BookPrice = posTx.Price; else BookPrice = posTx.Price.Convert((1 / posTx.ExchangeRate), posTx.Price.Underlying.BaseCurrency); // In Instrument currency Money bookChange = newSize.CalculateAmount(posTx.Price, true); BookChangeIC = bookChange; BookValueIC = bookChange; // Convert to Base Currency if (!((ICurrency)bookChange.Underlying).IsBase) bookChange = bookChange.Convert(1 / posTx.ExchangeRate, ((ICurrency)bookChange.Underlying).BaseCurrency, 7); BookChange = bookChange; BookValue = bookChange; AvgOpenExRate = Math.Round(posTx.ExchangeRate, 7); } }