// aktualizacja danych na liście po odebraniu ich z sieci
        internal void Update(DTO.OrderData data)
        {
            var order = list.Where(o => o.Id == data.BrokerId).SingleOrDefault();

            if (order != null)
            {
                order.Update(data);
            }
            else
            {
                list.Add(new BosOrder(Account, data));
            }
        }
		// aktualizacja informacji o bieżących zleceniach
		private void OrderUpdateHandler(OrderData orderData)
		{
			var account = Accounts[orderData.AccountNumber];
			account.Orders.Update(orderData);
			InvokeUpdate(account);
		}
		// wewnętrzna obsługa komunikatu "ExecRpt"
		// - wywołuje zdarzenie "OrderUpdateEvent"
		private void ExecReportMsgHandler(ExecutionReportMsg msg)
		{
			if (OrderUpdateEvent != null)
			{
				var order = new OrderData();
				order.AccountNumber = msg.Account;
				order.BrokerId = msg.BrokerOrderId2;
				order.ClientId = msg.ClientOrderId;

				// UWAGA: odczyt danych z komunikatu ExecRpt odbywa się "na czuja"... bo dostarczoną 
				// z Bossy/Comarchu dokumentacją na ten temat to można sobie najwyżej w kominku podpalić.
				// Generalnie wszystko jest rozjechane, ale te statusy zleceń to już chyba po pijaku pisali.
				//   Tyle - musiałem to tu napisać !!!  ;-P
				// Bo mnie już krew zalewa, jak widzę co ten NOL3 wysyła i gdzie (w których polach)... 
				// I że w ogóle musiałem te wszystkie możliwe przypadki samodzielnie analizować...
				// A jak za miesiąc przestanie działać, bo coś tam "naprawią", to chyba kogoś postrzelę ;-(


				// raport o wykonaniu - być może cząstkowym - danego zlecenia
				// (z praktyki wynika, że zawsze wcześniej dostaniemy "pełen" ExecRpt z pozostałymi
				// informacjami o tym zleceniu... dlatego teraz odbieramy sobie tylko raport z tej transakcji)
				if (msg.ExecType == ExecReportType.Trade)
				{
					order.TradeReport = new OrderTradeData();
					order.TradeReport.Time = (DateTime)msg.TransactionTime;
					order.TradeReport.Price = (decimal)msg.Price;  // LastPrice !?
					order.TradeReport.Quantity = (uint)msg.Quantity;  // LastQuantity !?
					order.TradeReport.NetValue = (decimal)msg.NetMoney;
					order.TradeReport.Commission = (decimal)msg.CommissionValue;
				}
				else
				{
					// w pozostałych przypadkach wygląda na to, że lepiej się oprzeć na polu "Status"
					// (bo ExecType czasem jest, czasem nie ma - różnie to z nim bywa... a Status jest chyba zawsze)
					order.StatusReport = new OrderStatusData();
					order.StatusReport.Status = ExecReport_GetStatus(msg);
					order.StatusReport.Quantity = (uint)msg.CumulatedQuantity;
					order.StatusReport.NetValue = (decimal)msg.NetMoney;
					order.StatusReport.Commission = (decimal)msg.CommissionValue;  // czasem == 0, ale dlaczego!? kto to wie... 

					// pozostałe dane - żeby się nie rozdrabniać - też aktualizujemy za każdym razem
					// (teoretycznie wystarczyłoby przy "new" i "replace"... ale czasem jako pierwsze
					// przychodzi np. "filled" i kto wie co jeszcze innego, więc tak będzie bezpieczniej)
					order.MainData = new OrderMainData();
					order.MainData.CreateTime = (DateTime)msg.TransactionTime;
					order.MainData.Instrument = msg.Instrument.Convert();
					order.MainData.Side = (msg.Side == Fixml.OrderSide.Buy) ? BosOrderSide.Buy : BosOrderSide.Sell;
					order.MainData.PriceType = ExecReport_GetPriceType(msg);
					if (order.MainData.PriceType == PriceType.Limit)
						order.MainData.PriceLimit = msg.Price;
					if ((msg.Type == OrderType.StopLimit) || (msg.Type == OrderType.StopLoss))
						order.MainData.ActivationPrice = msg.StopPrice;
					order.MainData.Quantity = (uint)msg.Quantity;
					order.MainData.MinimumQuantity = (msg.TimeInForce == OrdTimeInForce.WuA) ? msg.Quantity : msg.MinimumQuantity;
					order.MainData.VisibleQuantity = msg.DisplayQuantity;
					order.MainData.ImmediateOrCancel = (msg.TimeInForce == OrdTimeInForce.WiA);
					order.MainData.ExpirationDate = (msg.TimeInForce == OrdTimeInForce.Date) ? msg.ExpireDate : null;
				}

				// wywołanie zdarzenia z przygotowanymi danymi
				OrderUpdateEvent(order);
			}
		}
		// Metoda IBosClient do modyfikacji istniejącego zlecenia.
		public void OrderReplace(OrderData data)
		{
			Debug.WriteLine("\nOrderReplace...");
			using (Socket socket = NolClient.GetSyncSocket())
			{
				OrderReplaceRequestMsg request = new OrderReplaceRequestMsg();
				request.Account = data.AccountNumber;
				request.BrokerOrderId2 = data.BrokerId;
				request.Instrument = FixmlInstrument.Find(data.MainData.Instrument);
				request.Side = (data.MainData.Side == BosOrderSide.Buy) ? OrderSide.Buy : OrderSide.Sell;
				request.Type = Order_GetType(data.MainData);
				request.Price = data.MainData.PriceLimit;
				request.StopPrice = data.MainData.ActivationPrice;
				request.Quantity = data.MainData.Quantity;
				request.MinimumQuantity = data.MainData.MinimumQuantity;
				request.DisplayQuantity = data.MainData.VisibleQuantity;
				request.TimeInForce = Order_GetTimeInForce(data.MainData);
				request.ExpireDate = data.MainData.ExpirationDate;
				request.Send(socket);
				ExecutionReportMsg response = new ExecutionReportMsg(socket);
			}
			Debug.WriteLine("OrderReplace OK\n");
		}
		// Metoda IBosClient do anulowania istniejącego zlecenia.
		public void OrderCancel(OrderData data)
		{
			Debug.WriteLine("\nOrderCancel...");
			using (Socket socket = NolClient.GetSyncSocket())
			{
				OrderCancelRequestMsg request = new OrderCancelRequestMsg();
				request.Account = data.AccountNumber;
				request.BrokerOrderId2 = data.BrokerId;
				request.Instrument = FixmlInstrument.Find(data.MainData.Instrument);
				request.Side = (data.MainData.Side == BosOrderSide.Buy) ? OrderSide.Buy : OrderSide.Sell;
				request.Quantity = data.MainData.Quantity;
				request.Send(socket);
				ExecutionReportMsg response = new ExecutionReportMsg(socket);
			}
			Debug.WriteLine("OrderCancel OK\n");
		}
		// Metoda IBosClient do składania nowego zlecenia.
		public string OrderCreate(OrderData data)
		{
			string clientId;
			Debug.WriteLine("\nOrderCreate...");
			using (Socket socket = NolClient.GetSyncSocket())
			{
				NewOrderSingleMsg request = new NewOrderSingleMsg();
				clientId = request.ClientOrderId;  // automatycznie przydzielone kolejne Id
				request.Account = data.AccountNumber;
				request.CreateTime = data.MainData.CreateTime;
				request.Instrument = FixmlInstrument.Find(data.MainData.Instrument);
				request.Side = (data.MainData.Side == BosOrderSide.Buy) ? OrderSide.Buy : OrderSide.Sell;
				request.Type = Order_GetType(data.MainData);
				request.Price = data.MainData.PriceLimit;
				request.StopPrice = data.MainData.ActivationPrice;
				request.Quantity = data.MainData.Quantity;
				request.MinimumQuantity = data.MainData.MinimumQuantity;
				request.DisplayQuantity = data.MainData.VisibleQuantity;
				request.TimeInForce = Order_GetTimeInForce(data.MainData);
				request.ExpireDate = data.MainData.ExpirationDate;
				request.Send(socket);
				ExecutionReportMsg response = new ExecutionReportMsg(socket);
			}
			Debug.WriteLine("OrderCreate OK\n");
			return clientId;
		}
		/// <summary>
		/// Wysłanie do systemu nowego zlecenia z podanymi parametrami. 
		/// <para>Zobacz też metody klasy BosInstrument: Order, Buy, Sell - które od razu określają, 
		/// którego instrumentu dane zlecenie ma dotyczyć i ewentualnie prezyzują też stronę transakcji (kupno/sprzedaż)</para>
		/// </summary>
		/// <param name="account">Rachunek, na który zostaje przeznaczone to zlecenie.</param>
		/// <param name="instrument">Instrument, którego walory chcemy kupić/sprzedać.</param>
		/// <param name="side">Zlecenie kupna (BosOrderSide.Buy) czy sprzedaży (BosOrderSide.Sell).</param>
		/// <param name="price">Limit ceny, jaki wstawiamy do zlecenia (BosPrice.PKC/PCR/PCRO... lub po prostu kwota).</param>
		/// <param name="activationPrice">Ewentualny limit aktywacji zlecenia (null, jeśli aktywowane od razu, bez stop'a).</param>
		/// <param name="quantity">Liczba walorów, jaką zamierzamy kupić/sprzedać.</param>
		/// <param name="minimumQuantity">Minimalna liczba walorów, jaka musi się zrealizować, albo zlecenie będzie anulowane.
		/// Podając tutaj to samo, co w polu "quantity", uzyskujemy zlecenie typu "WuA".</param>
		/// <param name="visibleQuantity">Liczba walorów ujawniana w arkuszu ofert ("WUJ").</param>
		/// <param name="immediateOrCancel">Czy to zlecenie typu "WiA" (to, co nie wykona się natychmiast, jest od razu anulowane).</param>
		/// <param name="expirationDate">Data ważności zlecenia (null, jeśli tylko na bieżącą sesję).</param>
		public static void Create(BosAccount account, BosInstrument instrument, 
			BosOrderSide side, BosPrice price, decimal? activationPrice,
			uint quantity, uint? minimumQuantity, uint? visibleQuantity, bool immediateOrCancel, DateTime? expirationDate)
		{
			var data = new OrderData();
			data.AccountNumber = account.Number;
			data.MainData = new OrderMainData();
			data.MainData.CreateTime = DateTime.Now;
			data.MainData.Instrument = instrument.Convert();
			data.MainData.Side = side;
			data.MainData.PriceType = price.Type;
			data.MainData.PriceLimit = price.NumValue;
			data.MainData.ActivationPrice = activationPrice;
			data.MainData.Quantity = quantity;
			data.MainData.MinimumQuantity = minimumQuantity;
			data.MainData.VisibleQuantity = visibleQuantity;
			data.MainData.ImmediateOrCancel = immediateOrCancel;
			data.MainData.ExpirationDate = expirationDate;
			account.api.Connection.OrderCreate(data);
			// TODO: Zastanawiam się jeszczcze m.in. co z ClientId, TradeDate... i czy w ogóle byłby sens
			// od razu tworzyć taki nowy obiekt BosOrder (zamiast zaczekać aż sam się doda przy OrderUpdate).
		}
		// przygotowanie obiektu transportowego na podstawie bieżącego obiektu
		private OrderData GetData()
		{
			var data = new OrderData();
			data.AccountNumber = Account.Number;
			data.BrokerId = Id;
			data.MainData = new OrderMainData();
			data.MainData.CreateTime = CreateTime;
			data.MainData.Instrument = Instrument.Convert();
			data.MainData.Side = Side;
			data.MainData.PriceType = Price.Type;
			data.MainData.PriceLimit = Price.NumValue;
			data.MainData.ActivationPrice = ActivationPrice;
			data.MainData.Quantity = Quantity;
			data.MainData.MinimumQuantity = MinimumQuantity;
			data.MainData.VisibleQuantity = VisibleQuantity;
			data.MainData.ImmediateOrCancel = ImmediateOrCancel;
			data.MainData.ExpirationDate = ExpirationDate;
			return data;
		}
		// aktualizacja danych obiektu po odebraniu ich z sieci
		internal void Update(OrderData data)
		{
			if (data.MainData != null) Update(data.MainData);
			if (data.StatusReport != null) Update(data.StatusReport);
			if (data.TradeReport != null) Update(data.TradeReport);
		}
		// konstruktor wywoływany w klasie BosOrders, gdy pojawia się nowy numer zlecenia
		internal BosOrder(BosAccount account, OrderData data)
		{
			Account = account;
			Id = data.BrokerId;
			Update(data);
		}