/// <summary> /// /// </summary> /// <returns></returns> public virtual OrderValidationResult Validate() { // Buy -> Check Cash (Buying Power) // Sell -> Check the Positions string message = ""; OrderValidationResult retVal = new OrderValidationResult(OrderValidationSubType.Success, ""); //Check if an instruction exist - Invalid_InstructionExists retVal = checkInstructionExists(); if (retVal.Type != OrderValidationSubType.Success) return retVal; if (Side == Side.Buy) { if (!Account.AccountOwner.IsStichting) { // check the Cash -> Buying Power check // BP = All Cash (incl cash management fund) - Open Orders - Open Trades (Not Approved) Money currentOrderAmount; Money totalCashAmount; string oldPriceWarning = ""; if (!IsMonetary && ((ISecurityOrder)this).TradedInstrument.SecCategory.Key == SecCategories.CashManagementFund) totalCashAmount = Account.TotalPositionAmount(PositionAmountReturnValue.Cash); else totalCashAmount = Account.TotalPositionAmount(PositionAmountReturnValue.BothCash); if (totalCashAmount == null || totalCashAmount.IsZero) { message = string.Format("This order ({0}) can not be entered since there is no cash.", Value.ToString()); return new OrderValidationResult(OrderValidationSubType.Invalid_NoCash, message); } if (IsSizeBased) { // if closure -> check not another buy order already exists. OrderValidationResult buyCloseCheck = checkBuyCloseOrders(); if (buyCloseCheck.Type != OrderValidationSubType.Success) return buyCloseCheck; // Get the Price of the Instrument IPriceDetail priceDetail = RequestedInstrument.CurrentPrice; if (priceDetail == null) { message = string.Format("The order validation is not very accurate since no current price is available for {0}.", Value.Underlying.Name); return new OrderValidationResult(OrderValidationSubType.Warning_NoCurrentPrice, message); } else { Money accruedInterest = ((ISecurityOrder)this).AccruedInterest; currentOrderAmount = ((Money)(Value.CalculateAmount(priceDetail.Price) + Commission + accruedInterest)).CurrentBaseAmount; if (priceDetail.IsOldDate) { oldPriceWarning = string.Format("The order validation is not very accurate since the last available price ({0}) is from {1}.", priceDetail.Price.ToString(), priceDetail.Date.ToShortDateString()); } } } else { currentOrderAmount = GrossAmountBase; //// Check when Foreign currency amount -> if foreign currency is available if (!Value.Underlying.ToCurrency.IsBase) { ICashPosition posFx = Account.Portfolio.PortfolioCashGL.GetPosition(Value.Underlying.ToCurrency); Money orderAmtFx = Account.OpenOrdersForAccount.TotalAmountInSpecifiedNominalCurrency((ICurrency)Value.Underlying); if (posFx == null) { message = string.Format("This order ({0}) can not be placed since the account doesn't have a {1} position.", GrossAmount.DisplayString, Value.Underlying.Name); retVal = new OrderValidationResult(OrderValidationSubType.Invalid_NoCash, message); } else if (!((Money)(posFx.SettledSize - orderAmtFx - GrossAmount)).Sign) { string messageOpenOrders = ""; if (orderAmtFx != null && orderAmtFx.IsNotZero) messageOpenOrders = string.Format(" minus the open order amount ({0}) in {1}", orderAmtFx.ToString(), Value.Underlying.Name); message = string.Format("This order ({0}) exceeds the current {1} cash amount ({2}){3}.", GrossAmount.DisplayString, Value.Underlying.Name, posFx.SettledSize.ToString(), messageOpenOrders); retVal = new OrderValidationResult(OrderValidationSubType.Invalid_NotEnoughCash, message); } if (retVal.Type != OrderValidationSubType.Success) { retVal.Message += Environment.NewLine + string.Format("Place a {0} order instead.", Account.AccountOwner.StichtingDetails.BaseCurrency.ToString()); return retVal; } } } // Consider both Buy & Sell orders Money openOrderAmount = Account.OpenOrderAmount(OpenOrderAmountReturnValue.Gross); if (!((Money)(totalCashAmount - openOrderAmount - currentOrderAmount)).Sign) { if (openOrderAmount != null && openOrderAmount.IsNotZero) message = string.Format(" minus the open order amount ({0})", openOrderAmount.DisplayString); message = string.Format("This order ({0}) exceeds the total cash amount ({1}){2}.", currentOrderAmount.DisplayString, totalCashAmount.DisplayString, message); retVal = new OrderValidationResult(OrderValidationSubType.Invalid_NotEnoughCash, message); } retVal.Message += oldPriceWarning; if (oldPriceWarning != string.Empty && retVal.Type == OrderValidationSubType.Success) { retVal.Type = OrderValidationSubType.Warning_OldPrice; } } } else { // Get the current Position size InstrumentSize positionSize = null; IFundPosition position = Account.Portfolio.PortfolioInstrument.GetPosition((ITradeableInstrument) RequestedInstrument); if (position != null) positionSize = position.Size; if (positionSize == null || positionSize.IsZero) { message = string.Format("You tried to sell {0} but there are no positions found.", RequestedInstrument.Name); return new OrderValidationResult(OrderValidationSubType.Invalid_NoPosition, message); } // Get the positions size of the order PredictedSize predSize; if (!IsSizeBased) { // Amount based -> Get the Price/ExRate predSize = RequestedInstrument.PredictSize(Amount); // If there is no Price/ExRate found -> warning if (predSize.Status == PredictedSizeReturnValue.NoRate) { message = string.Format("The order validation is not very accurate since no current {0} is available for {1}.", (RequestedInstrument.IsCash ? "exchangerate" : "price"), Value.Underlying.Name); return new OrderValidationResult(OrderValidationSubType.Warning_NoCurrentPrice, message); } } else { predSize = new PredictedSize(Value, DateTime.Now); } // Get the open order size InstrumentSize openOrderSize = null; if (Account.OpenOrdersForAccount != null && Account.OpenOrdersForAccount.Count > 0) openOrderSize = Account.OpenOrdersForAccount.TotalSize(RequestedInstrument); if (!((InstrumentSize)(positionSize + (predSize.Size + openOrderSize))).Sign) { message = string.Format("You tried to sell {0} {1} but in the portfolio only {2} positions were found", predSize.Size.Abs().ToString(), RequestedInstrument.Name, positionSize.ToString()); if (openOrderSize != null && openOrderSize.IsNotZero) message += Environment.NewLine + string.Format(" and order(s) existed for {0}.", openOrderSize.ToString()); else message += "."; retVal = new OrderValidationResult(OrderValidationSubType.Invalid_NotEnoughPosition, message); } if (predSize.Status == PredictedSizeReturnValue.OldRateDate) { retVal.Message += (retVal.Message == string.Empty ? "" : Environment.NewLine) + string.Format("The order validation is not very accurate since the last available {0} ({1}) is from {2}.", (RequestedInstrument.IsCash ? "exchangerate" : "price"), predSize.Rate, predSize.RateDate.ToShortDateString()); if (retVal.Type == OrderValidationSubType.Success) { retVal.Type = OrderValidationSubType.Warning_OldPrice; } } } // Check opposite orders OrderValidationResult sideCheck = checkSideOrders(); if (sideCheck.Type != OrderValidationSubType.Success) { retVal.Message += (retVal.Message == string.Empty ? "" : Environment.NewLine) + sideCheck.Message; if (retVal.Type == OrderValidationSubType.Success) { retVal.Type = sideCheck.Type; } } return retVal; }
/// <summary> /// Get the educated guess of the size of a instrument for a amount of money /// </summary> /// <param name="inputAmount"></param> /// <returns></returns> public override PredictedSize PredictSize(Money inputAmount) { PredictedSize retVal = new PredictedSize(PredictedSizeReturnValue.NoRate); Money amount; if (CurrentPrice != null) { retVal.RateDate = CurrentPrice.Date; if (inputAmount.Underlying.Equals(CurrentPrice.Price.Underlying)) retVal.Size = inputAmount.CalculateSize(CurrentPrice.Price); else { amount = inputAmount.Convert(CurrentPrice.Price.Underlying); retVal.Size = amount.CalculateSize(CurrentPrice.Price); } retVal.Rate = currentPrice.Price.ToString(); } return retVal; }
public override PredictedSize PredictSize(Money inputAmount) { PredictedSize retVal = new PredictedSize(PredictedSizeReturnValue.NoRate); return retVal; }