вторник, 29 мая 2018 г.

EventLogWindow and ProcessTask Right Sequence

 public void Init(IEventLog evl)
        {
            if (evl == null)
                throw new NullReferenceException($"{GetType().Name}: EventLog = null)");

            EventLog = evl;
            EventLog.EventLogChangedEvent += CallbackEventLogOperation1;

            // EventLog Need for Init ProcessTask !!!!

            EventLog.AddItem(EvlResult.SUCCESS, EvlSubject.INIT,
               GetType().Name, Title, "Init Begin", "", "");

            IsProcessTaskInUse = true;
            SetupProcessTask();

            Capasity = CapasityVal;
            CapasityLimit = CapasityLimitVal;

            EventLog.AddItem(EvlResult.SUCCESS, EvlSubject.INIT,
               GetType().Name, Title, "Init Finish", "", "");
        }

  private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            LstEventLog.ItemsSource = EventLogItems;
            ProcessTask?.Start();

        }

Components with ProcessTask

1. EventLogs
2. Tickers
3. QuikTradeTerminal
4. Dde
5. EventHub

1. EventLogWindow3
2. Position_Window3
3. PositionTotal_Window3
4. Transactions_Window
5. ...

понедельник, 28 мая 2018 г.

FileRecursiveSync

1. EventLog with Process Task
2. Files as you see down
Key#09CD532C-E21C-487E-87C0-287A44C5073A#.pem
Upload By Ftp uncorrectly: Name is cutted
File: 
"Key#09CD532C-E21C-487E-87C0-287A44C5073A#.pem"
After Ftp Transfer wil be "Key"

StellaMaris Update Root

180320

.htaccess

SetEnvIf GEOIP_COUNTRY_CODE RU AllowCountry

Deny from env=AllowCountry

четверг, 24 мая 2018 г.

Totals3 Window with ProcessTask

public partial class PositionTotalsWindow3
    {
        public bool IsProcessTaskInUse { get; set; }
        private void SetupProcessTask()
        {
            if (!IsProcessTaskInUse)
            {
                _evl.Evlm2(EvlResult.WARNING, EvlSubject.TECHNOLOGY, Name, Name,
                MethodBase.GetCurrentMethod().Name, "ProcessTask Will NOT BE USED",
                ToString());
                return;
            }
            ProcessTask = new ProcessTask<IEventArgs>();
            ProcessTask.Init(_evl);
            // ProcessTask.Parent = this;
            ProcessTask.TimeInterval = 1000;
            ProcessTask.IsEveryItemPushProcessing = false;
            ProcessTask.ItemsProcessingAction = InsertItemsIntoObserveCollection;

            _evl.Evlm2(EvlResult.SUCCESS, EvlSubject.TECHNOLOGY, Name, Name,
                MethodBase.GetCurrentMethod().Name, "ProcessTask IS USED NOW",
                ProcessTask?.ToString());
        }

        private void InsertItemsIntoObserveCollection(IEnumerable<IEventArgs> args)
        {
            Dispatcher.BeginInvoke((ThreadStart)(() =>
            {
                foreach (var arg in args)
                  ProcessPosition(arg);
            }
           ));
        }
        private void ProcessPosition(IEventArgs arg)
        {
            var ip = arg?.Object as IPosition2;
            if (ip == null)
                return;
            PositionTotalNpc2 p;
            switch (arg.OperationKey)
            {
                case "UI.POSITIONS.TOTAL.INSERT":
                    
                        p = new PositionTotalNpc2(ip);
                        PositionCollection.Insert(0, p);
                        
                        this.Title = "Totals ( " + PositionCollection.Count + " )";
                    break;
                case "UI.POSITIONS.TOTAL.ADD":
                case "UI.POSITIONS.TOTAL.ADD.TOEND":
                    
                        p = new PositionTotalNpc2(ip);
                        PositionCollection.Add(p);
                        
                        this.Title = "Totals ( " + PositionCollection.Count + " )";
                    
                    break;
                case "UI.POSITIONS.TOTAL.ADDNEW":

                        p = PositionCollection.FirstOrDefault(po => po.Key == ip.Key);
                        if (p == null)
                            PositionCollection.Add(new PositionTotalNpc2(ip));
                        
                        this.Title = "Totals ( " + PositionCollection.Count + " )";
                   
                    break;
                case "UI.POSITIONS.TOTAL.DELETE":
                        
                        p = PositionCollection.FirstOrDefault(po => po.Key == ip.Key);
                        if (p != null)
                            PositionCollection.Remove(p);
                        this.Title = "Totals ( " + PositionCollection.Count + " )";
                   
                    break;

                case "UI.POSITIONS.TOTAL.UPDATE":
                       
                        p = PositionCollection.FirstOrDefault(po => po.Key == ip.Key);
                        p?.Update(ip);

                    break;
                case "UI.POSITIONS.TOTAL.ADDORUPDATE":
                        try
                        {
                            p = PositionCollection.FirstOrDefault(po => po.Key == ip.Key);
                            if (p != null)
                                p.Update(ip);
                            else
                                PositionCollection.Add(new PositionTotalNpc2(ip));
                            
                            this.Title = "Totals ( " + PositionCollection.Count + " )";
                        }
                        catch (Exception e)
                        {
                            _tx.SendExceptionMessage3("TotalsWindow", "Position2", "AddOrUpdate", ip.ToString(), e);
                        }                 
                    break;
            }
        }

        [XmlIgnore]
        public GS.ProcessTasks.ProcessTask<IEventArgs> ProcessTask { get; private set; }
        public void Start()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Start();
        }
        public void Stop()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Stop();
        }
    }

воскресенье, 20 мая 2018 г.

EventLogWindow3 with ProcessTask

new EventLogWindow3 with ProcessTask Instead EventLogWindow2

EventLogWindow2:
EventLog->Window.Callback->DispatcherTread->item(evli)->ObserveCollection everyone evli

EventLogWindow3:
EventLog->Window.Callback->ProcessTask.Queue.Push->Delay(1000ms)->
ProcessTask.ITEMS.Processing->DispatcherTread->ITEMS(IEnumerable<evli>)->ObserveCollection

ProcessTask SetUp

public bool IsProcessTaskInUse { get; set; }
        private void SetupProcessTask()
        {
            if (!IsProcessTaskInUse)
            {
                EventLog.Evlm2(EvlResult.WARNING, EvlSubject.TECHNOLOGY, Name, Name,
                MethodBase.GetCurrentMethod().Name, "ProcessTask Will NOT BE USED",
                ToString());
                return;
            }
            ProcessTask = new ProcessTask<IEventLogItem>();
            ProcessTask.Init(EventLog);
            // ProcessTask.Parent = this;
            ProcessTask.TimeInterval = 1000;
            ProcessTask.IsEveryItemPushProcessing = false;
            ProcessTask.ItemsProcessingAction = InsertItemsIntoObserveCollection;

            EventLog.Evlm2(EvlResult.SUCCESS, EvlSubject.TECHNOLOGY, Name, Name,
                MethodBase.GetCurrentMethod().Name, "ProcessTask IS USED NOW",
                ProcessTask?.ToString());
        }
        [XmlIgnore]
        public GS.ProcessTasks.ProcessTask<IEventLogItem> ProcessTask { get; private set; }
        public void Start()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Start();
        }
        public void Stop()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Stop();
        }

ProcessTask.ItemsHandler:

private void InsertItemsIntoObserveCollection(IEnumerable<IEventLogItem> evlis)
        {
            Dispatcher.BeginInvoke((ThreadStart)(() =>
            {
                foreach (var evli in evlis)
                    EventLogItems.Insert(0, evli);

                if (Capasity != 0 && CapasityLimit + Capasity <= EventLogItems.Count)
                    ClearSomeData(Capasity);
            }
            ));

        }


Context

Context, Context1, Context2

Differs
public interface IContext
    {
        IEventLog EventLog { get; }

       EventHub3 EventHub { get; }

       WorkTasks WorkTasks { get; }

        void Init();
        void Start();
        void Stop();
    }

 public interface IContext1
    {
        IEventLog EventLog { get; }

       EventHub3 EventHub { get; }

       WorkTasks4 WorkTasks { get; }

        void Init();
        void Start();
        void Stop();

        void DoWork();

    }

and EventHub3 Use in Both

пятница, 18 мая 2018 г.

QuikTerminal, ProcessTask Example to use ProcessTask

Here is example how to use ProcessTask (with IdleCycleAction inUse)

public sealed partial class QuikTradeTerminal
    {
        public bool IsProcessTaskInUse { get; set; }

        [XmlIgnore]

        public ProcessTask<IEventArgs1> ProcessTask { get; private set; }
        private void SetupProcessTask()
        {
            if (!IsProcessTaskInUse)
            {
                Evlm2(EvlResult.WARNING, EvlSubject.TECHNOLOGY, ParentName, Name,
                MethodBase.GetCurrentMethod().Name, "ProcessTask Will NOT BE USED",
                ToString());
                return;
            }
            
            ProcessTask = new ProcessTask<IEventArgs1>();
            ProcessTask.Init();
            ProcessTask.TimeInterval = 1000;
            ProcessTask.Parent = this;
            ProcessTask.IsEveryItemPushProcessing = true;
            //ProcessTask.ItemProcessingAction = args =>
            //{
            //    try
            //    {
            //        args.ProcessingAction(args);
            //    }
            //    catch (Exception e)
            //    {
            //        SendException(e);
            //    }
            //};
            ProcessTask.ItemProcessingAction = ItemProcessingAction;
            ProcessTask.IdlingCycleAction = ProcessTaskAdditionalWork;

            Evlm2(EvlResult.SUCCESS, EvlSubject.TECHNOLOGY, ParentName, Name,

                 MethodBase.GetCurrentMethod().Name, "ProcessTask IS USED NOW",
                 ProcessTask?.ToString());
        }

        public void Start()

        {
            SetupProcessTask();

            if(IsProcessTaskInUse)

                ProcessTask?.Start();
        }
        public void Stop()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Stop();
        }
        // ************************************************
        // ProcessTask Actions
        private void ItemProcessingAction(IEventArgs1 args)
        {
            try
            {
                args.ProcessingAction(args);
            }
            catch (Exception e)
            {
                SendException(e);
            }
        }
        // AdditionalWorks in IdlingCycleAction
        private void ProcessTaskAdditionalWork()
        {
            TradeResolveProcess();
            OrderResolveProcess();
        }
    }

воскресенье, 13 мая 2018 г.

QuikTerminal, ProcessTask

Так как для QuikTerminals нет Builder, пришлось хранить IsProcessTaskInUse в QuikTransactions

<QuikTransactions>
  <Name>Quik Transactions</Name>
  <Code>Quik Transactions</Code>
  <IsEnabled>true</IsEnabled>
  <IsEvlEnabled>true</IsEvlEnabled>
  <Category>Transactions</Category>
  <Entity>Transaction</Entity>
  <!-- Need for QuikTerminal -->

  <IsProcessTaskInUse>false</IsProcessTaskInUse>

</QuikTransactions>

Достается в QuikTerminal так:

Transactions = Builder.Build<QuikTransactions>(@"Init\QuikTransactions.xml", "QuikTransactions");
Transactions.Parent = this;

IsProcessTaskInUse = Transactions.IsProcessTaskInUse;      

SetupProcessTask();


private void SetupProcessTask()
        {
            if (!IsProcessTaskInUse)
            {
                Evlm2(EvlResult.WARNING, EvlSubject.TECHNOLOGY, ParentName, Name,
                MethodBase.GetCurrentMethod().Name, "ProcessTask Will NOT BE USED",
                ToString());
                return;
            }
            
            ProcessTask = new ProcessTask<IEventArgs1>();
            ProcessTask.Init();
            ProcessTask.TimeInterval = 1000;
            ProcessTask.Parent = this;
            ProcessTask.IsEveryItemPushProcessing = true;
            ProcessTask.ItemProcessingAction = args =>
            {
                try
                {
                    args.Action(args);
                }
                catch (Exception e)
                {
                    SendException(e);
                }
            };

            Evlm2(EvlResult.INFO, EvlSubject.TECHNOLOGY, ParentName, Name,
                MethodBase.GetCurrentMethod().Name, "ProcessTask Will be Used",
                ProcessTask.ToString());
        }

суббота, 12 мая 2018 г.

ProcessTask Setup in SubSystem

QuikTradeTerminal:

private void SetupProcessTask()
        {
            ProcessTask = new ProcessTask<IEventArgs1>();
            ProcessTask.Init();
            ProcessTask.TimeInterval = 1000;
            ProcessTask.Parent = this;
            ProcessTask.IsEveryItemPushProcessing = true;

// Item Processing
            ProcessTask.ItemProcessingAction = args =>
            {
                try
                {
                    args.Action(args);
                }
                catch (Exception e)
                {
                    SendException(e);
                }
            };
        }

private void SendReplyEventArgs(TransactionReplyItem tr)
        {
            var eargs = new EventArgs1
            {
                Process = "QuikTransactionsProcess",
                Category = "QuikTransactions",
                Entity = "TransactionReplyItem",
                Operation = "AddOrUpdate",
                Object = tr,
                Action = TransactionReplyResolve
            };
            ProcessTask?.EnQueue(eargs);
        }

public void TransactionReplyResolve(IEventArgs1 args)
        {
            var trReply = (TransactionReplyItem)args.Object;
            var dwTransId = trReply.TransId;
            var replyMessage = trReply.ReplyMessage;
            var nResult = trReply.Result;
            var nExtendedErrorCode = trReply.ExtendedErrorCode;
            var nReplyCode = trReply.ReplyCode;
            var dOrderNum = trReply.OrderNum;

            TransactionReplyEvent?.Invoke((int)nResult, (uint)dwTransId, dOrderNum);
...
    

Tickers:

public bool IsProcessTaskInUse { get; set; }

[XmlIgnore]
public GS.ProcessTasks.ProcessTask<string> ProcessTask { get; private set; }

        private void SetupProcessTask()
        {
            ProcessTask = new ProcessTask<string>();
            ProcessTask.Init();
            ProcessTask.TimeInterval = 1000;
            ProcessTask.Parent = this;
            ProcessTask.IsEveryItemPushProcessing = true;

// ItemS Processing
         ProcessTask.ItemsProcessingAction = QuoteStringsProcessing;
        }

        public void Start()
        {
            if(IsProcessTaskInUse)
                ProcessTask?.Start();
        }
        public void Stop()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Stop();
        }

public void QuoteStringsProcessing(IEnumerable<string> quotestrings)
        {
            try
            {
                foreach (var s in quotestrings)
...

EventLogs:

// Setup in .xml file
        public bool IsProcessTaskInUse { get; set; }
        private void SetupProcessTask()
        {
            ProcessTask = new ProcessTask<IEventLogItem>();
            ProcessTask.Init(this);
            ProcessTask.Parent = this;
            ProcessTask.TimeInterval = 1000;
            ProcessTask.IsEveryItemPushProcessing = false;
            ProcessTask.ItemProcessingAction = evli =>
            {
                try
                {
                    AddItem(evli);
                }
                catch (Exception e)
                {
                    SendException(e);
                    //Evlm2(EvlResult.FATAL, EvlSubject.PROGRAMMING,
                    //    GetType().Name, "ProcessTask", "Exception", e.Message);
                }
            };
        }
        [XmlIgnore]
        public GS.ProcessTasks.ProcessTask<IEventLogItem> ProcessTask { get; private set; }
        public void Start()
        {
            if(IsProcessTaskInUse)
                ProcessTask?.Start();
        }
        public void Stop()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Stop();
        }

public void Push(IEventLogItem queueItem)
        {
            if (IsProcessTaskInUse)
                ProcessTask.EnQueue(queueItem);
            else
                EvlQueue.Push(queueItem);
        }

EventHub:

 public bool IsProcessTaskInUse { get; set; }
        private void SetupProcessTask()
        {
            ProcessTask = new ProcessTask<IEventArgs>();
            ProcessTask.Init();
            ProcessTask.TimeInterval = 1000;
            ProcessTask.Parent = this;
            ProcessTask.IsEveryItemPushProcessing = true;
            ProcessTask.ItemProcessingAction = FireEventOperation;
        }
        [XmlIgnore]
        public GS.ProcessTasks.ProcessTask<IEventArgs> ProcessTask { get; private set; }
        public void Start()
        {
            if(IsProcessTaskInUse)
                ProcessTask?.Start();
        }
        public void Stop()
        {
            if (IsProcessTaskInUse)
                ProcessTask?.Stop();
        }
...

 protected void FireEventOperation(Events.IEventArgs args)
        {
            try
            {
                var key = args.Key;
                var evhubitem = GetByKey(key);
                if (evhubitem != null)
                    evhubitem.FireEvent(args.Sender, args);
...

public void FireEvent(object sender, Events.IEventArgs eventArgs)
        {
            EventHandler?.Invoke(sender, eventArgs);
...

пятница, 11 мая 2018 г.

Save some some sql scripts for fast restore in future

use DbTrade2

DECLARE @DT DateTime
DECLARE @DT1 DateTime
DECLARE @DT2 DateTime

DECLARE @CUR_TABLE VARCHAR(100)
SET @CUR_TABLE = 'ORDERS'
-- ORDERS
SET @DT1 = GETDATE()
SELECT @DT1 [DateTime], DB_NAME()  [DB_NAME], @CUR_TABLE [TABLE]

SET @DT = GeTDATE()
Select @DT [DateTime], 'Orders To Delete' as Operation, Count(*) as Cnt, 
Min(Cast( Modified as Date)) as Dt1, Max(Cast( Modified as Date)) as Dt2
From Orders
-- Go

DELETE from Orders
where Cast( Created as Date) NOT IN
(
select top 2 Cast( o.Created as Date) dt
from Orders o
Group by Cast( o.Created as Date)
Order by Cast( o.Created as Date) DESC
)
--GO
select  Cast( o.Created as Date) DT, Count(*) OrdersCount
from Orders o
Group by Cast( o.Created as Date)
Order by Cast( o.Created as Date) DESC
--GO

SET @DT = GeTDATE()
Select @DT [DateTime],'Orders After Delete' as Operation, Count(*) as Cnt, 
Min(Cast( Modified as Date)) as Dt1, Max(Cast( Modified as Date)) as Dt2
From Orders
--Go

SET @DT2 = GeTDATE()

Select @DT2 [DateTime], DB_NAME() [DB_NAME], @CUR_TABLE [TABLE],
CAST((@dt2 - @dt1) AS Time) as 'Elapsed_Time'
GO

-- TRADES
Select 'Trades To Delete' as Operation, Count(*) as Cnt, 
Min(Cast( DT as Date)) as Dt1, Max(Cast( DT as Date)) as Dt2
From Trades
Go

DELETE from Trades
where Cast( DT as Date) NOT IN
(
select top 2 Cast( DT as Date) DT
from Trades o
Group by Cast( DT as Date)
Order by Cast( DT as Date) DESC
)
GO
select  Cast( DT as Date) dt, Count(*) TradesCount
from Trades o
Group by Cast( DT as Date)
Order by Cast( DT as Date) DESC
GO

Select 'Trades After Delete' as Operation, Count(*) as Cnt, 
Min(Cast( DT as Date)) as Dt1, Max(Cast( DT as Date)) as Dt2
From Trades
Go

-- DEALS
SELECT 'DEALS' [Context]
GO

DECLARE @DT DateTime
DECLARE @DT1 DateTime
DECLARE @DT2 DateTime

DECLARE @CUR_TABLE VARCHAR(100)

SET @CUR_TABLE = 'DEALS'

SET @DT1 = GETDATE()
SELECT @DT1 [DateTime], DB_NAME()  [DB_NAME], @CUR_TABLE [CUR_TABLE]

Select 'Deals Count' as Operation
--go
Select 'Deals Count' as Operation, Count(*) as Cnt,
Min(Cast( DT as Date)) as Dt1, Max(Cast( DT as Date)) as Dt2
from Deals
-- go

SET @DT2 = GETDATE()
SELECT @DT2 [DateTime], DB_NAME()  [DB_NAME],  @CUR_TABLE [CUR_TABLE],
CAST((@dt2 - @dt1) AS Time) as 'Elapsed_Time'

--select  Cast( DT as Date) dt, Count(*) DealsCount
--FROM Deals
--Group by Cast( DT as Date)
--Order by Cast( DT as Date) DESC

--Select 'Deals Delete' as Operation

--DELETE from Deals
--where Cast( DT as Date) NOT IN
--(
--select top 3 Cast( DT as Date) dt
--from Deals o
--Group by Cast( DT as Date)
--Order by Cast( DT as Date) DESC
--)
--GO
--select  Cast( DT as Date) dt, Count(*) DealsCount
--from Deals o
--Group by Cast( DT as Date)
--Order by Cast( DT as Date) DESC
--GO

-- EventLogs
--USE EventLog
--EXECUTE dbo.SP_EVLS_CLEAR_2_DAYS
--USE EventLog1
--EXECUTE dbo.SP_EVLS_CLEAR_2_DAYS
--USE EvlContext
--EXECUTE dbo.SP_EVLS_CLEAR_2_DAYS

/*
Use EventLog
Select 'EventLog To Delete' as Operation, Count(*) as Cnt, 
Min(Cast( DT as Date)) as Dt1, Max(Cast( DT as Date)) as Dt2
From EventLogItems
Go
DELETE from EventLogItems 
where Cast( DT as Date) NOT IN
(
select top 2 Cast( DT as Date) dt
from EventLogItems o
Group by Cast( DT as Date)
Order by Cast( DT as Date) DESC
)
GO
select Cast( DT as Date) dt, Count(*) as EvliCount
from EventLogItems o
Group by Cast( DT as Date)
Order by Cast( DT as Date) DESC
GO
Select 'EventLog After Delete' as Operation, Count(*) as Cnt, 
Min(Cast( DT as Date)) as Dt1, Max(Cast( DT as Date)) as Dt2
From EventLogItems
Go
*/

USE TimeSeries01
Declare @dt1 as DateTime, @dt2 as DateTime

SET @dt1 = GETDATE()
Select @dt1 as 'Start DateTIme'
delete from Bars
where id In
(
Select b.Id
FROM dbo.Bars b
INNER JOIN TimeSeries ts on b.BarSeriesId = ts.Id
INNER JOIN Tickers t on ts.TickerId = t.Id
inner join TradeBoards tb on t.TradeBoardId = tb.Id
Where (tb.Id = 2 Or tb.Id = 3) AND 
(cast(Dt as Time) < '10:00:00' OR cast(DT as Time) > '23:50:00')
)

SET @dt2  = GETDATE()
Select @dt2 as 'Finish DateTIme'
Select cast((@dt2 - @dt1) as Time) as 'ElapsedTime'

go

USE EventLog1
EXECUTE [dbo].[SP_EVLS_CLEAR_2_DAYS]
GO

USE EventLog
EXECUTE [dbo].[SP_EVLS_CLEAR_2_DAYS]
GO

USE EvlContext
EXECUTE [dbo].[SP_EVLS_CLEAR_2_DAYS]

GO


Cardinal Changes in EventLog, TradeContext with ProcessTask

1. Cardinal Changes in Eventlog.
From Threads to ProcessTask<TInput>

EventLogs.cs 

 public interface IEventLogs : IEventLog, IHaveQueue<IEventLogItem>
    {
        void Start();
        void Stop();
    }

private void SetupProcessTask()
        {
            ProcessTask = new ProcessTask<IEventLogItem>();
            ProcessTask.Init(this);
            ProcessTask.Parent = this;
            ProcessTask.ItemProcessingAction = evli =>
            {
                try
                {
                    AddItem(evli);
                }
                catch (Exception e)
                {
                    Evlm2(EvlResult.FATAL, EvlSubject.PROGRAMMING,
                        GetType().Name, "ProcessTask", "Exception", e.Message);
                }
            };
        }

public void Start()
        {
            ProcessTask?.Start();
        }
        public void Stop()
        {

            ProcessTask?.Stop();

        }

EventLogs.Init()
{
...
...

 SetupProcessTask();

}

TradeContext5.cs

 // 2018.05.11 new EventLog with Processor Inside ProcessTask<IEvlItem>              

((IEventLogs)EventLog)?.Start();


TradeContext51.cs   // Good Buy Threads

 // 2018.05.11 
                // UIProcess.RegisterProcess("EventLog Dequeue Process", "EventLog.DeQueue",

                //    1000, 0, null, ((IEventLogs) EventLog).DeQueueProcess, null);

WpfTradeContext CloseWindow:

EventHandlers.cs

 private void WindowClosed(object sender, EventArgs e)
        {
            _tx.Stop();
            //Thread.Sleep(5000);
            
            _tx.Close();

            ((IEventLogs)_evl)?.Stop();

        }