コード例 #1
0
ファイル: Order.cs プロジェクト: adchang/demo_exchange
        /// <summary>
        /// <c>Order</c> constructor.
        /// <br><c>Id</c>: Auto-gen GUID</br>
        /// <br><c>CreatedTimestamp</c>: Auto-gen UTC high fidelity timestamp</br>
        /// <br><c>Status</c>: Defaults to Open</br>
        /// <br><c>OpenQuantity</c>: Defaults to Quantity</br>
        /// <br><c>StrikePrice</c>: Defaults to OrderPrice</br>
        /// <br><c>ToBeCanceledTimestamp</c>: Defaults to 0 for Market orders, end of day for Day orders, and <c>TIME_IN_FORCE_TO_BE_Cancelled_DAYS</c> for Good Til Canceled orders.</br>
        /// </summary>
        // TODO: Should make this private; public only Entity and Request constructors
        public OrderBL(String accountId, OrderAction action, String ticker, OrderType type,
                       int quantity, decimal orderPrice, OrderTimeInForce timeInForce)
        {
            CheckNotNullOrWhitespace(accountId, paramName: nameof(accountId));
            CheckNotNullOrWhitespace(ticker, paramName: nameof(ticker));
            CheckArgument(quantity > 0, message: IOrderModel.ERROR_QUANTITY_IS_0);
            if (OrderType.OrderMarket.Equals(type))
            {
                if (orderPrice != 0)
                {
                    throw new ArgumentException(IOrderModel.ERROR_ORDER_PRICE_MARKET_NOT_0);
                }
            }
            else
            {
                if (orderPrice <= 0)
                {
                    throw new ArgumentException(IOrderModel.ERROR_ORDER_PRICE_IS_0);
                }
            }

            base.OrderId          = Guid.NewGuid();
            base.CreatedTimestamp = Now;
            base.AccountId        = Guid.Parse(accountId);
            base.Status           = OrderStatus.OrderOpen;
            base.Action           = action;
            base.Ticker           = ticker;
            base.Type             = type;
            base.Quantity         = quantity;
            base.OpenQuantity     = quantity;
            base.OrderPrice       = orderPrice;
            base.StrikePrice      = orderPrice;
            base.TimeInForce      = timeInForce;
            if (OrderType.OrderMarket.Equals(type))
            {
                base.ToBeCanceledTimestamp = 0;
            }
            else
            {
                long toBeCancel = 0;
                switch (TimeInForce)
                {
                case OrderTimeInForce.OrderDay:
                    toBeCancel = MidnightIct;
                    break;

                case OrderTimeInForce.OrderGoodTilCanceled:
                    toBeCancel = base.CreatedTimestamp + (TimeSpan.TicksPerDay * TIME_IN_FORCE_TO_BE_Cancelled_DAYS);
                    break;

                case OrderTimeInForce.OrderMarketClose:
                    toBeCancel = MidnightSaturdayIct;
                    break;
                }

                base.ToBeCanceledTimestamp = toBeCancel;
            }
        }
コード例 #2
0
        public static string ToDeribitString(this OrderTimeInForce tif)
        {
            switch (tif)
            {
            case OrderTimeInForce.fill_or_kill:
                return("fill_or_kill");

            case OrderTimeInForce.good_til_cancelled:
                return("good_til_cancelled");

            case OrderTimeInForce.immediate_or_cancel:
                return("immediate_or_cancel");

            default:
                throw new Exception();
            }
        }
コード例 #3
0
ファイル: BrokerWrapperIb.cs プロジェクト: gyantal/SQLab
        public int PlaceOrder(Contract p_contract, TransactionType p_transactionType, double p_volume, OrderExecution p_orderExecution, OrderTimeInForce p_orderTif, double? p_limitPrice, double? p_stopPrice, double p_estimatedPrice, bool p_isSimulatedTrades)
        {

            Order order = new Order();
            switch (p_transactionType)
            {
                case TransactionType.BuyAsset:
                    order.Action = "BUY";
                    break;
                case TransactionType.SellAsset:
                    order.Action = "SELL";
                    break;
                default:
                    throw new Exception($"Unexpected transactionType: {p_transactionType}");
            }

            order.TotalQuantity = p_volume;
            if (p_limitPrice != null)
                order.LmtPrice = (double)p_limitPrice;

            switch (p_orderExecution)
            {
                case OrderExecution.Market:
                    order.OrderType = "MKT";
                    break;
                case OrderExecution.MarketOnClose:
                    order.OrderType = "MOC";
                    break;
                default:
                    throw new Exception($"Unexpected OrderExecution: {p_orderExecution}");
            }

            switch (p_orderTif)
            {
                case OrderTimeInForce.Day:  // Day is the default, so don't do anything
                    order.Tif = "DAY";
                    break;
                default:
                    throw new Exception($"Unexpected OrderTimeInForce: {p_orderTif}");
            }

            int p_realOrderId = NextOrderId++;
            OrderSubscriptions.TryAdd(p_realOrderId, new OrderSubscription() { Contract = p_contract, Order = order });
            if (!p_isSimulatedTrades)
                ClientSocket.placeOrder(p_realOrderId, p_contract, order);
            return p_realOrderId;
        }
コード例 #4
0
        internal int PlaceOrder(GatewayId p_gatewayIdToTrade, double p_portfolioMaxTradeValueInCurrency, double p_portfolioMinTradeValueInCurrency,
                                Contract p_contract, TransactionType p_transactionType, double p_volume, OrderExecution p_orderExecution, OrderTimeInForce p_orderTif, double?p_limitPrice, double?p_stopPrice, bool p_isSimulatedTrades, double p_oldVolume, StringBuilder p_detailedReportSb)
        {
            Gateway?userGateway = m_gateways.FirstOrDefault(r => r.GatewayId == p_gatewayIdToTrade);

            if (userGateway == null || !userGateway.IsConnected)
            {
                Utils.Logger.Error($"ERROR. PlacingOrder(). GatewayIdToTrade {p_gatewayIdToTrade} is not found among connected Gateways or it is not connected.");
                return(-1);
            }

            var rtPrices = new Dictionary <int, PriceAndTime>()
            {
                { TickType.MID, new PriceAndTime() }
            };                                                                                             // MID is the most honest price. LAST may happened 1 hours ago

            if (m_mainGateway != null)
            {
                m_mainGateway.BrokerWrapper.GetAlreadyStreamedPrice(p_contract, ref rtPrices);
            }
            int virtualOrderId = userGateway.PlaceOrder(p_portfolioMaxTradeValueInCurrency, p_portfolioMinTradeValueInCurrency, p_contract, p_transactionType, p_volume, p_orderExecution, p_orderTif, p_limitPrice, p_stopPrice, rtPrices[TickType.MID].Price, p_isSimulatedTrades, p_oldVolume, p_detailedReportSb);

            return(virtualOrderId);
        }
コード例 #5
0
ファイル: BrokerWrapperYF.cs プロジェクト: gyantal/SQLab
 public int PlaceOrder(Contract p_contract, TransactionType p_transactionType, double p_volume, OrderExecution p_orderExecution, OrderTimeInForce p_orderTif, double? p_limitPrice, double? p_stopPrice, double p_estimatedPrice, bool p_isSimulatedTrades)
 {
     return new Random().Next(10000);    // time dependent seed. Good.
 }
コード例 #6
0
ファイル: Gateway.cs プロジェクト: gyantal/SQLab
        // PlayTransactionsViaBroker(). Consider these use-cases:
        // ******* 1. Problem: if VBroker1 is LONG IWM, VBroker2 is Short IWM at MOC, it cancels out each other(with Minfilter), there is no real life trade, which is OK.
        // However, there were 2 virtual transactions, that Gateway should give back, because VBroker1 and VBroker2 wants to write something to the Portfolio in the DB.
        //+Solution:
        //    - PlayTransactionsViaBroker() always gives back the prices (except in simulation mode); (even if minFilter was applied), Because we need it for the DB. If minfilter was applied, it gives back Volume = 0; showing it was not executed
        //    - PlayTransactionsViaBroker() signals whether an portfolioItem was executed or not (small are not executed) (in a flag or somewhere); it signals by changing the Volume to 0; (minFilter or maxFilter was applied)
        //    - even if an item is not executed, the BrokerTask can write them into the Portfolios (it is his own decision)
        //        + IF	there is at last 1 sub-strategy, in which this is significant amount enough (non-negligible) (we need per strategy minFilter values too; call it significancy; so don't confuse with TradeMin)
        //        + IF it is written into at least 1 sub-strategy portfolio, then All other sub-strategy portfolios are updated with the 'minor/manor' trades
        //        + invariant: keep real/simulated trade values equal; means: if +1 was traded, the aggregate written into DB should be 1 as well
        //        for example; there is 51 substrategy. One shorts 101 IWM, other 50 buys 2 IWM each. The aggregateIntent is short 1. The aggregateReal is 0 (minFilter skip).
        //        We have to update the virtual portfolios: but the aggregateSimulated should be 0 too. (that is the invariant)


        // ******* 2. LimitOrder execution policy:
        //- Determine targetPrice = MidPrice = (Ask+Bid)/2 
        //- convert it to 2 decimals (the smallest unit is 1 penny in the Exchange)
        //- send the order to the Broker with this targetPrice;
        //> Repeat from here
        //    - wait 10 seconds
        //    - cancel the order
        //    - wait some seconds until the Cancelation is confirmed
        //        - sometimes the cancellation fails. In that case, probably the original order were executed; handle it as completed;
        //        after calling cancelOrder(...) you must wait for it to be acknowledged i.e. orderStatus(...) returns with status=="Cancelled" or perhaps status=="Filled" and go from there. 

        //    if Repeat = 5, don't chase it further
        //        break;

        //    Method 1: (implemented)
        //    If the TargetPrice is < 100
        //        - add an extra penny to the target price (if it is a Buy order or Cover order)
        //        - OR subtract an extra penny to the target price (if it is a Sell or Short order)

        //    If the targetPrice is in [100.. 200]
        //        - add an extra 0.02 to the target price (if it is a Buy order or Cover order)
        //        - OR subtract an extra 0.02 to the target price (if it is a Sell or Short order)

        //    If the targetPrice is in [200.. ]
        //        - add an extra 0.05 to the target price (if it is a Buy order or Cover order)
        //        - OR subtract an extra 0.05 to the target price (if it is a Sell or Short order)

        //    Method 2: (Laszlo's idea: not yet implemented)
        //    - query the CurrentMidPrice (askBidprice) again (not based on previus) and set the targetPrice = BidPrice 
        //    this one is good in case of the Exploding stocks; that moves up 1% every 10 seconds (adding 1 penny cannot catch them)

        //    - insert the new order with the new targetPrice
        //> Repeat unti here


        // 3. ***** MOC orders: before Placing them, check current Open MOC orders
        // We can subscribe to all the current OrdersInfo. For MOC orders for example, before PlaceOrder() we should check that if there is already an MOC order then we Modify that (or Cancel&Recreate)

        // 4. *****  Glitch protections:
        //+ check the MaxTradeSize of the bxml file. : MaxTradeUsdValue
        //+ check the number of Trades in the last 10 minutes < 20; After that, stop everything.
        //+ check the $volume of those trades based on last day price (SQ DB SQL usage).; it should be < 1$ Mil in the last 10 minutes

        internal int PlaceOrder(double p_portfolioMaxTradeValueInCurrency, double p_portfolioMinTradeValueInCurrency, Contract p_contract, TransactionType p_transactionType, double p_volume, OrderExecution p_orderExecution, OrderTimeInForce p_orderTif, double? p_limitPrice, double? p_stopPrice, double p_estimatedPrice, bool p_isSimulatedTrades, StringBuilder p_detailedReportSb)
        {
            // 1. Glitch protections
            int virtualOrderID = GetUniqueVirtualOrderID;
            if (double.IsNaN(p_estimatedPrice) || Math.Abs(p_estimatedPrice) < 0.000)
            {   // we want HealthMonitor to be notified with StrongAssert, but continue with other orders
                Utils.Logger.Error("PlaceOrder(): 'double.IsNaN(p_estimatedPrice) || Math.Abs(p_estimatedPrice) < 0.001' failed. Not Safe to do the trade without estimating its value. Crash here.");
                return virtualOrderID;      // try to continue with other PlaceOrders()
            }
            double estimatedTransactionValue = p_volume * p_estimatedPrice;
            double maxAllowedTradeValue = IbAccountMaxTradeValueInCurrency;
            if (p_portfolioMaxTradeValueInCurrency < maxAllowedTradeValue)
                maxAllowedTradeValue = p_portfolioMaxTradeValueInCurrency;
            if (estimatedTransactionValue > maxAllowedTradeValue)  // if maxFilter is breached, safer to not trade at all. Even if it is an MOC order and can be grouped with other orders. Safer this way.
            {
                string errStr = $"Warning. MaxFilter is breached. Transaction is MaxFilter (IbAccount: ${IbAccountMaxTradeValueInCurrency:F0}, Portfolio: ${p_portfolioMaxTradeValueInCurrency:F0}) skipped: {p_contract.Symbol} {p_volume:F0}: $ {estimatedTransactionValue}";
                Utils.ConsoleWriteLine(ConsoleColor.Red, true, errStr);
                Utils.Logger.Warn(errStr);
                return virtualOrderID;
            }
            if (estimatedTransactionValue > (maxAllowedTradeValue/1.5))
            {
                //>When simulated order is 50% range of MaxTradeable, send a warning email to administrator to modify it in VBroker and redeploy. It is not likely that a  strategy will move 50% per day.
                string warnStr = $"Warning. Trade will commence, but MaxFilter is 50% away to be breached. Modify MaxTradeValue params (IbAccount or Portfolio) in VBroker and redeploy. Transaction is MaxFilter (IbAccount: ${IbAccountMaxTradeValueInCurrency:F0}, Portfolio: ${p_portfolioMaxTradeValueInCurrency:F0}). Trade: {p_contract.Symbol} {p_volume:F0}: $ {estimatedTransactionValue}";
                StrongAssert.Fail(Severity.NoException, warnStr);
            }

            if (estimatedTransactionValue < p_portfolioMinTradeValueInCurrency)
            {
                Utils.Logger.Info("p_portfolioMinTradeValueInCurrency usage is not implemented yet.");
            }

            DateTime utcNow = DateTime.UtcNow;
            int nLatestOrders = 0;
            double estimatedUsdSizeSumRecently = 0.0;
            lock (VirtualOrders)   // safety checks
            {
                foreach (var latestOrder in VirtualOrders.Where(r => (utcNow - r.SubmitTime).TotalMinutes < 10.0))
                {
                    nLatestOrders++;
                    estimatedUsdSizeSumRecently += latestOrder.EstimatedUsdSize;
                }
            }
            if (nLatestOrders >= m_maxNOrdersRecentlyAllowed)
            {
                Utils.Logger.Error($"nLatestOrders >= m_maxNOrdersRecentlyAllowed. This is for your protection. Transaction {p_contract.Symbol} is skipped. Set Settings to allow more.");
                return virtualOrderID;      // try to continue with other PlaceOrders()
            }
            if (estimatedUsdSizeSumRecently >= m_IbAccountMaxEstimatedValueSumRecentlyAllowed)
            {
                Utils.Logger.Error($"estimatedUsdSizeSum >= m_maxEstimatedUsdSumRecentlyAllowed. This is for your protection. Transaction {p_contract.Symbol} is skipped. Set Settings to allow more.");
                return virtualOrderID;      // try to continue with other PlaceOrders()
            }

            // 2. Execute different orderTypes MKT, MOC
            // vbOrderId and ibOrderID is different, because some Limit orders, or other tricky orders are executed in real life by many concrete IB orders
            // or there are two opposite vbOrder that cancels each other out at MOC, therefore there is no ibOrder at all
            Utils.ConsoleWriteLine(null, false, $"{(p_isSimulatedTrades ? "Simulated" : "Real")} {p_transactionType}  {p_volume} {p_contract.Symbol} (${estimatedTransactionValue:F0})");
            Utils.Logger.Info($"{(p_isSimulatedTrades?"Simulated":"Real")} {p_transactionType} {p_volume} {p_contract.Symbol} (${estimatedTransactionValue:F0})");
            p_detailedReportSb.AppendLine($"{(p_isSimulatedTrades ? "Simulated" : "Real")} {p_transactionType}  {p_volume} {p_contract.Symbol} (${estimatedTransactionValue:F0})");

            if (p_orderExecution == OrderExecution.Market)
            {
                // Perform minFilter skipped here. But use estimatedTransactionValue. We get the estimatedPrice from the Main Gateway
                if (estimatedTransactionValue < AllowedMinUsdTransactionValue)
                {
                    Utils.ConsoleWriteLine(null, false, $"Transaction is MinFilter (${AllowedMinUsdTransactionValue:F0}) skipped: {p_contract.Symbol} {p_volume:F0}");
                    Utils.Logger.Info($"Transaction is MinFilter (${AllowedMinUsdTransactionValue:F0}) skipped: {p_contract.Symbol} {p_volume:F0}");
                    lock (VirtualOrders)
                        VirtualOrders.Add(new VirtualOrder() { OrderId = virtualOrderID, SubmitTime = DateTime.UtcNow, EstimatedUsdSize = 0.0, OrderExecution = p_orderExecution, OrderStatus = OrderStatus.MinFilterSkipped });
                    return virtualOrderID;
                }

                int ibRealOrderID = BrokerWrapper.PlaceOrder(p_contract, p_transactionType, p_volume, p_orderExecution, p_orderTif, p_limitPrice, p_stopPrice, p_estimatedPrice, p_isSimulatedTrades);
                lock (VirtualOrders)
                    VirtualOrders.Add(new VirtualOrder() { OrderId = virtualOrderID, SubmitTime = DateTime.UtcNow, EstimatedUsdSize = estimatedTransactionValue, RealOrderIds = new List<int>() { ibRealOrderID }, OrderExecution = p_orderExecution, OrderStatus = OrderStatus.Submitted, });
                lock (RealOrders)
                    RealOrders.Add(new RealOrder() { OrderId = ibRealOrderID, VirtualOrderIds = new List<int>() { virtualOrderID } });
                
            } else if (p_orderExecution == OrderExecution.MarketOnClose)
            {
                // MOC orders need more consideration. Checking current MOC orders of the gateway, modifying it, etc. and 1 realOrders can be many VirtualOrders
                // (MinFilter orders may be played here if there is already a bigger order under Excetion. However, this 'nice' feature is not necessary.)

                // 1. Get a list of current orders from BrokerGateway
                // 2. If this ticker that I want to trade is in the list, don't create a new order, but modify that one.
                // 3. Otherwise, create a new Order

                // !!! Now, we only play UWM, TWM at MOC orders, so in real life, there will be no order Clash. Later, implement it properly. Now, assume that there is no other MOC order for this stock.
                // in the future implement MOC order in a general way. One RealOrder can mean many Virtual MOC orders.

                // Perform minFilter skipped here. But use estimatedTransactionValue. We get the estimatedPrice from the Main Gateway
                if (estimatedTransactionValue < AllowedMinUsdTransactionValue)
                {
                    Utils.Logger.Warn($"Transaction is MinFilter (${AllowedMinUsdTransactionValue:F0}) skipped: {p_contract.Symbol} {p_volume:F0}");
                    lock (VirtualOrders)
                        VirtualOrders.Add(new VirtualOrder() { OrderId = virtualOrderID, SubmitTime = DateTime.UtcNow, EstimatedUsdSize = 0.0, OrderExecution = p_orderExecution, OrderStatus = OrderStatus.MinFilterSkipped });
                    return virtualOrderID;
                }

                int ibRealOrderID = BrokerWrapper.PlaceOrder(p_contract, p_transactionType, p_volume, p_orderExecution, p_orderTif, p_limitPrice, p_stopPrice, p_estimatedPrice, p_isSimulatedTrades);
                lock (VirtualOrders)
                    VirtualOrders.Add(new VirtualOrder() { OrderId = virtualOrderID, SubmitTime = DateTime.UtcNow, EstimatedUsdSize = estimatedTransactionValue, RealOrderIds = new List<int>() { ibRealOrderID }, OrderExecution = p_orderExecution, OrderStatus = OrderStatus.Submitted, });
                lock (RealOrders)
                    RealOrders.Add(new RealOrder() { OrderId = ibRealOrderID, VirtualOrderIds = new List<int>() { virtualOrderID } });

            }
            else
            {
                Utils.Logger.Error("Only the Simple Market order is implemented. MOC orders need more consideration. Checking current MOC orders of the gateway, modifying it, etc.");
            }

            return virtualOrderID;
        }
コード例 #7
0
ファイル: GatewaysWatcher.cs プロジェクト: gyantal/SQLab
        internal int PlaceOrder(GatewayUser p_gatewayUserToTrade, double p_portfolioMaxTradeValueInCurrency, double p_portfolioMinTradeValueInCurrency, 
            Contract p_contract, TransactionType p_transactionType, double p_volume, OrderExecution p_orderExecution, OrderTimeInForce p_orderTif, double? p_limitPrice, double? p_stopPrice, bool p_isSimulatedTrades, StringBuilder p_detailedReportSb)
        {
            if (!m_isReady)
                return -1;

            Gateway userGateway = m_gateways.FirstOrDefault(r => r.GatewayUser == p_gatewayUserToTrade);
            if (userGateway == null)
            {
                Utils.Logger.Error($"ERROR. PlacingOrder(). GatewayUserToTrade {p_gatewayUserToTrade} is not found among connected Gateways.");
                return -1;
            }

            var rtPrices = new Dictionary<int, PriceAndTime>() { { TickType.MID, new PriceAndTime() } };   // MID is the most honest price. LAST may happened 1 hours ago
            m_mainGateway.BrokerWrapper.GetMktDataSnapshot(p_contract, ref rtPrices);
            int virtualOrderId = userGateway.PlaceOrder(p_portfolioMaxTradeValueInCurrency, p_portfolioMinTradeValueInCurrency, p_contract, p_transactionType, p_volume, p_orderExecution, p_orderTif, p_limitPrice, p_stopPrice, rtPrices[TickType.MID].Price, p_isSimulatedTrades, p_detailedReportSb);
            return virtualOrderId;
        }
コード例 #8
0
ファイル: BrokerWrapperTest.cs プロジェクト: gyantal/SQLab
 public int PlaceOrder(Contract p_contract, TransactionType p_transactionType, double p_volume, OrderExecution p_orderExecution, OrderTimeInForce p_orderTif, double? p_limitPrice, double? p_stopPrice, double p_estimatedPrice, bool p_isSimulatedTrades)
 {
     throw new NotImplementedException();
 }