【发布时间】:2017-05-26 07:55:59
【问题描述】:
我有一个用于算法股票交易的小程序。代码必须在我的 8 核台式机上循环大约 192 万亿次。我想过租一台 64 核的机器来运行它,但它并不划算。
只是这段代码。但是 for 循环必须在每个要计算的柱上循环(大约 180 万),然后它循环检查匹配项的列表大约是 800k 项。
我现在能想到的加快速度的唯一方法是删除匹配的项目,因为它只发生一次(日期时间)。
还有其他人有办法加快这段代码的速度吗?我的桌面野兽需要大约 45 小时才能运行一次程序迭代。
基本上我所做的是计算每个柱,查看当前柱 DateTime 是否与我在手动创建的 CSV 文件中的 DateTime 匹配。然后从对象列表中,获取交易方向并设置一个布尔值来持仓。
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; }
}
}
速度变慢的罪魁祸首是 CalcBar() 方法中的 For 循环。
【问题讨论】:
-
在
tradeList.ElementAt(i).direction上使用开关可能会更快。 -
使用字典或以
time为键的排序树进行交易而不是列表。字典查找摊销为 O(1),树查找为 O(lgN)。在这里,咨询费用为 100 万美元 - 每次循环迭代的百万分之一肯定不会过多:) -
你可以试试Parallel.For
-
您的
GetEcal函数很慢,因为您正在将整个文件读入内存 (ReadAllLines),然后由于ToList()而复制数组两次。然后使用String.Split也会不必要地浪费内存 - 您应该使用基于有限状态机的 CSV 解析器 - 这将显着减少内存使用和运行时间。 -
索引!索引!索引!索引。尤其是在贸易清单不经常变化的情况下。
标签: c# .net algorithmic-trading