3

我有开始日期列表和结束日期列表。他们排序...

start_dates = [
    datetime.date(2009, 11, 5), datetime.date(2009, 11, 13), 
    datetime.date(2009, 11, 25), datetime.date(2009, 11, 26), 
    datetime.date(2009, 12, 4), datetime.date(2009, 12, 7), 
    datetime.date(2009, 12, 29), datetime.date(2009, 12, 30)]

end_dates = [
    datetime.date(2009, 10, 1), datetime.date(2009, 10, 2), 
    datetime.date(2009, 10, 9), datetime.date(2009, 10, 12), 
    datetime.date(2009, 11, 4), datetime.date(2009, 12, 14), 
    datetime.date(2009, 12, 15)]

开始日期代表我们收到建议购买股票的日期。结束日期是我们收到出售建议的日期。建议的来源是不同的,我们正在回测如果我们使用来自一个来源的买入建议,而使用来自另一个来源的卖出建议会发生什么。因此,我们有两个日期序列,我们希望将它们分解成对 - 或间隔 - 我们将在这些日期上持有股票头寸。

因此,我们将从 start_dates 中选择一个日期来决定何时购买股票:11 月 5 日我们买入一个头寸。然后我们在 end_dates 中循环寻找第一个卖出建议:12 月 14 日。然后重复,当我们从一个来源获得建议时没有持有头寸时买入,当我们从另一个来源持有头寸时卖出。

你可能会说我们想要在循环遍历的两个列表中的哪一个之间切换。

因此上面的输入生成:

result = (
  (datetime.date(2009, 11, 5), datetime.date(2009, 12, 14)),
  (datetime.date(2009, 12, 29), None)
)

我在 for 循环中使用 for 循环,想知道是否没有更好的方法。性能令人感兴趣,因为它将在 40 年的时间跨度内应用于数千种场景;一些列表涉及数千个日期。

4

4 回答 4

2

编辑

这应该与len(start_dates)+len(end_dates)

def date_range(start_dates, end_dates):
    result = []

    start_i = 0
    end_i = 0

    while start_i<len(start_dates):
        while end_i<len(end_dates) and start_dates[start_i]>end_dates[end_i]:
            end_i += 1
        if end_i == len(end_dates):
            result.append((start_dates[start_i], None))
            break
        result.append((start_dates[start_i], end_dates[end_i]))
        while start_i<len(start_dates) and start_dates[start_i]<=end_dates[end_i]:
            start_i += 1
        end_i += 1

    return result

用法:

In  : start_dates = [
   ....:     datetime.date(2009, 11, 5), datetime.date(2009, 11, 13),
   ....:     datetime.date(2009, 11, 25), datetime.date(2009, 11, 26),
   ....:     datetime.date(2009, 12, 4), datetime.date(2009, 12, 7),
   ....:     datetime.date(2009, 12, 29), datetime.date(2009, 12, 30)]

In : end_dates = [
   ....:     datetime.date(2009, 10, 1), datetime.date(2009, 10, 2),
   ....:     datetime.date(2009, 10, 9), datetime.date(2009, 10, 12),
   ....:     datetime.date(2009, 11, 4), datetime.date(2009, 12, 14),
   ....:     datetime.date(2009, 12, 15)]

In : date_range(start_dates, end_dates)
Out:
[(datetime.date(2009, 11, 5), datetime.date(2009, 12, 14)),
 (datetime.date(2009, 12, 29), None)]

In : start_dates = [
   ....:     datetime.date(2009, 11, 5), datetime.date(2009, 11, 13),
   ....:     datetime.date(2009, 11, 25), datetime.date(2009, 11, 26),
   ....:     datetime.date(2009, 12, 4), datetime.date(2009, 12, 7),
   ....:     datetime.date(2009, 12, 29), datetime.date(2009, 12, 30)]

In : end_dates = [
   ....:     datetime.date(2009, 10, 1), datetime.date(2009, 10, 2),
   ....:     datetime.date(2009, 10, 9), datetime.date(2009, 10, 12),
   ....:     datetime.date(2009, 11, 7), datetime.date(2009, 12, 14), # changed (2009, 11, 4) -> (2009, 11, 7)
   ....:     datetime.date(2009, 12, 15)]

In : date_range(start_dates, end_dates)
Out:
[(datetime.date(2009, 11, 5), datetime.date(2009, 11, 7)),
 (datetime.date(2009, 11, 13), datetime.date(2009, 12, 14)),
 (datetime.date(2009, 12, 29), None)]
于 2012-08-24T04:35:31.050 回答
1

我认为这应该可以获取日期元组,但我不能建议你不使用 for 循环的方式,因为它可能会变得更复杂。

逻辑非常简单明了。

result = []
for startd in start_dates:
    if not result or result[-1][1] is not None and startd>result[-1][1]:
    #can use 'len(result)==0' instead of 'not result'
        for endd in end_dates:
            if endd>startd:
                result.append((startd,endd))
                break
        else:
            result.append((start,None))
    if result[-1][1] is None:
        break

result = tuple(result)
print result
于 2012-08-24T06:35:56.573 回答
1

我终于把它归结为:

    trades = []
    enddate = datetime.date(1900, 1, 1)
    try:
        for startdate in startdates:
            if enddate <= startdate:
                enddate = enddates.next()
                while enddate <= startdate:
                    enddate = enddates.next()
                trades.append((startdate, enddate))
    except StopIteration:
        trades.append((startdate, None))

感谢那些提出问题和回答的人。不知何故,这个小谜题成了我的执念,但我想我终于把这件事做死了,应该继续我的生活。最后真的很简单 - 令人惊讶的是花了多少工作才使它变得如此简单!

于 2012-08-25T06:38:44.227 回答
0

这个怎么样。

all_dates = start_dates.expand(end_dates)
all_dates.sort()

look_for_start = 1;
date = []
start_date = None
end_date = None
for i in range(len(all_dates)):
   if look_for_start and all_dates[i] in start_dates:
     start_date = all_dates[i]
     look_for_start = 0;

   elsif !look_for_start and all_dates[i] in end_dates:
     end_date = all_dates[1]
     look_for_start = 1;

   if start_date == end_date:
     end_date == None
     look_for_start = 0;

   if start_date != None and end_date != None;
     date.append((start_date,end_date))
     start_date = None
     end_date = None

在此之后,您尽可能拥有带有结束日期的 start_dates。只需获取剩余的 start_dates 集并将其结束日期设置为 None

于 2012-08-24T03:59:13.317 回答