加速这段代码 - 192万亿()循环

Cno*_*ote 4 .net c# algorithmic-trading

我有一个小程序,我用于算法股票交易.代码必须在我的8核桌面计算机上循环大约192万亿次.我想租用一台64核机器来运行它,但这不符合成本效益.

这只是代码.但for循环必须在每个要计算的条上循环(大约180万),然后循环检查匹配的列表大约是800k项.

我现在能想到加速它的唯一方法是删除匹配的项目,因为它只发生一次(DateTime).

有没有其他人有办法加快这段代码的速度?这需要我的桌面野兽大约45个小时来完成程序的一次迭代.

基本上我正在做的是计算每个条形图,寻找当前条形DateTime是否与我手工创建的CSV文件中的DateTime相匹配.然后从列表对象中,我抓住交易方向并设置一个bool来占据一个位置.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using PowerLanguage.Function;
using ATCenterProxy.interop;
using System.IO;
using System.IO.Compression;

namespace PowerLanguage.Strategy
{
    public class Ecal_v1 : SignalObject
    {
        public List<Trades> tradeList = new List<Trades>();
        public List<string> csvList = new List<string>();
        public bool exitOn24 = false;
        public string ecalPath = @"C:\Users\Skynet\OneDrive\Trading\Economic Calendars\backtest1.csv";
        PowerLanguage.Indicator.Bollinger_Bands bb;

        public Ecal_v1(object _ctx):base(_ctx){}

        //[Input]
        //public bool exitOn24 { get; set; }

        [Input]
        public double bbTopOffset { get; set; }
        775
        [Input]
        public double bbBotOffset { get; set; }

        [Input]
        public double longTPMod { get; set; }

        [Input]
        public double shortTPMod { get; set; }

        [Input]
        public double longSLMod { get; set; }

        [Input]
        public double shortSLMod { get; set; }

        //[Input]
        //public double buyTrail { get; set; }

        //[Input]
        //public double sellTrail { get; set; }

        double bbUpperDiff;
        double bbLowerDiff;
        double bbBasis;
        double longTP;
        double shortTP;
        double longSL;
        double shortSL;
        double ptValue;
        public DateTime tradeTime;

        private IOrderMarket longEntry, shortEntry, longExit, shortExit;

        protected override void Create()
        {
            // create variable objects, function objects, order objects etc.
            bb = ((PowerLanguage.Indicator.Bollinger_Bands)AddIndicator("Bollinger_Bands"));

            longEntry = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, EOrderAction.Buy));
            shortEntry = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, EOrderAction.SellShort));
            longExit = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, EOrderAction.Sell));
            shortExit = OrderCreator.MarketNextBar(new SOrderParameters(Contracts.Default, EOrderAction.BuyToCover));
        }

        protected override void StartCalc()
        {
            // assign inputs 
            GetEcal();
            ptValue = Bars.Point;

            longTP = longTPMod;
            longSL = longSLMod;
            shortTP = shortTPMod;
            shortSL = shortSLMod;

        }

        protected override void CalcBar()
        {
            bool LE = false;
            bool SE = false;
            bool LX = false;
            bool SX = false;

            for(int i=0; i<tradeList.Count; i++)
            {
                if(Bars.Time[0] == tradeList.ElementAt(i).time)
                {
                    if (tradeList.ElementAt(i).direction == "Up")
                    {
                        LE = true;
                        tradeList.RemoveAt(i);
                    }
                    else if (tradeList.ElementAt(i).direction == "Down")
                    {
                        SE = true;
                        tradeList.RemoveAt(i);
                    }
                    else
                    {

                    }
                }
            }

            if(exitOn24 == true)
            {
                if (Bars.Time[0] > tradeTime.AddHours(24))
                {
                    LX = true;
                    SX = true;
                }
            }

            if (StrategyInfo.MarketPosition == 0)
            {
                if (LE)
                {
                    longEntry.Send();
                    tradeTime = Bars.Time[0];
                    setLongStops();     
                }
                else if (SE)
                {
                    shortEntry.Send();
                    tradeTime = Bars.Time[0];
                    setShortStops();        
                }
            }

            else if (StrategyInfo.MarketPosition > 0)
            {
                if (LX)
                {
                    longExit.Send();
                }
                else if (LE)
                {
                    longEntry.Send();
                    tradeTime = Bars.Time[0];
                    setLongStops();
                }
                else
                {
                    CurSpecOrdersMode = ESpecOrdersMode.PerPosition;
                    GenerateStopLossPt(longSL);
                    GenerateProfitTargetPt(longTP);
                    //GenerateTrailingStopPt(buyTrail);
                }
            }

            else if (StrategyInfo.MarketPosition < 0)
            {
                if (SX)
                {
                    shortExit.Send();
                }
                else if (SE)
                {
                    shortEntry.Send();
                    tradeTime = Bars.Time[0];
                    setShortStops();
                }
                else
                {
                    CurSpecOrdersMode = ESpecOrdersMode.PerPosition;
                    GenerateStopLossPt(shortSL);
                    GenerateProfitTargetPt(shortTP);
                    //GenerateTrailingStopPt(sellTrail);
                }
            }
        }

        private void GetEcal()
        {
            csvList = File.ReadAllLines(ecalPath).Skip(1).ToList();
            foreach(string line in csvList)
            {
                string[] values = line.Split(',');
                tradeList.Add(new Trades { time = Convert.ToDateTime(values[0]), direction = values[1] });
            }
        }
    }


    public class Trades
    {
        public DateTime time { get; set; }
        public string direction { get; set; }
    }


}
Run Code Online (Sandbox Code Playgroud)

减速的罪魁祸首是CalcBar()方法中的For循环.

Ada*_*cki 7

你试过介绍这种方法吗?我们的信息太少了.例如,最昂贵的操作可能是

Bars.Time[0] == tradeList.ElementAt(i).time
Run Code Online (Sandbox Code Playgroud)

我们不知道.您应该先对其进行分析.

下一步是什么...

tradeList.ElementAt(i).direction == "Up"
Run Code Online (Sandbox Code Playgroud)

不要使用字符串.字符串很慢.你可以在这里使用enums,它将被优化为整数和整数比对比字符串快得多.

不要使用ElementAt方法.只使用[]运算符.它更快.

考虑使用Dictionary而不是List.它比列表快得多.列表必须通过每个元素来找到你需要的东西.字典没有.这可能是非常关键的部分.

考虑使用整数而不是dateTimes.将整数视为秒.它会比DateTime快.

并使用Parallel.ForEach而不是普通的.然后它将使用其他核心.普通的可能仅使用一个核心.

哦,还有一件事.如果是库存应用程序,也许您可​​以尝试使用神经网络?但这是一个完全不同的故事.


Mau*_*tro 6

  • RemoveAt将处理列表的其余部分,以便在您删除一个项目之后移动每个项目.看到这里.在您的情况下,这会产生巨大的成本.

    解决方案是使用一个临时列表,在其中添加稍后将删除的元素,从循环(sourceList.Except(removedList)); 或者只是以某种方式标记您的项目已删除,并且从不触及源列表.

  • 您正在将内存中的所有行加载到内存中以便读取它们并在每行中创建一个强类型对象.

    您可以逐行读取文件,并创建对象.

  • ElementAt可能比索引器慢.由于您使用的是列表,因此只需使用[]访问项目以避免疑惑.

  • 要使用更少的内存并进行更快的比较,请direction使用"向上""向下"值进行枚举.

如果不并行化代码,则不会利用许多核心.一旦你得到正确的thigs,如果程序仍然需要几个小时,你可以尝试Parallel.For而不是.在这种情况下,"将项目标记为已删除的解决方案"比使用并发列表更简单,更合适,并将其与要删除的项目一起提供.