转换时间&日期到相对时间(CSV处理)

时间:2016-02-22 17:21:31

标签: java date csv time stock

我目前处于编写多方面投资算法的早期阶段。我目前正在研究的部分涉及使用具有LASSO惩罚的图形高斯模型来找到可用于为投资策略提供信息的相互依赖性。我目前正在尝试使用JAVA预处理历史CSV数据输入,并使用相关数据创建新的CSV输出文件。

我用来测试处理算法的原始小规模示例数据(最终将用于路透社Eikon实时订阅源)采用txt / CSV格式。我有一个包含文本文件的文件夹,其中包含纽约证券交易所的许多股票的历史数据。虽然有8列,但我感兴趣的三个(为了在创建协方差矩阵之前进行预处理的目的,它将输入'GLASSO')是Date,Time&开盘价。开盘价格栏不需要预处理,因此可以输入新的,噪音较小的输出文件。

我的问题是如何将两列(日期和时间)转换为单个时间测量。我认为最明显的方法是在我的数据中找到最早的时间点并将其用作点0(以秒为单位)。然后,我需要将每个时间和日期组合转换为单个列,显示输出CSV文件中超过原始时间点的秒数。一旦完成此操作而不是文件路径规范,我希望能够指定一个文件夹,程序循环遍历所有文本文件,查找相关列并将所有列输出到单个CSV文件中。

在实践中希望看起来像这样:

CSV标题和一个NYSE txt文件中的第一个条目 -

“日期,时间,打开,高,低,关闭,音量,OpenInt

2016-02-03,15:35:00,37.27,37.36,37.17,37.29,25274,0"

所以基本上如果第一个条目是最早的时间参考:

2016-02-03,15:35:00 ='0'

2016-02-03,15:40:00 ='300'(5分钟为300秒)

只需重新进行迭代,输入就是一个包含数百个以下格式化CSV的文件夹:

专栏 - 1:日期 2:时间 3:开放 4:高 5:低 6:关闭 7:卷 8:OpenInt

输出是一个包含以下内容的CSV文件:

专栏 - 1:时间测量(距离最早入口点的距离) 2:每次测量条目的股票价格。

如果您有任何关于我如何做这件事的线索,请告诉我。如果有什么我可以澄清让您的生活更轻松,请随时告诉我,我知道我可以解释这个以一种不那么令人费解的方式。

2 个答案:

答案 0 :(得分:2)

以下是使用您提供的示例CSV行的示例。我更改了输入以更改秒数,因此您可以看到差异的工作原理:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Dater {

    String s1[] = {"2016-02-03,15:35:01,37.27,37.36,37.17,37.29,25274,0",  //1 sec after minDate
                    "2016-02-03,15:35:00,37.27,37.36,37.17,37.29,25274,0", //<-- minDate
                    "2016-02-03,15:35:02,37.27,37.36,37.17,37.29,25274,0"  //2 sec after minDate
                    };
    Date [] dates;
    Date minDate;

    public Dater()
    {
        minDate = new Date();
        makeDates();

        for (Date d : dates)
        {
            System.out.println(diffSeconds(d));
        }
    }
    public void makeDates()
    {
        dates = new Date[s1.length];
        int index = 0;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (String s : s1)
        {
            String [] split = s.split(",");
            String date = split[0];
            String time = split[1];

            try {
                dates[index] = formatter.parse(date + " " + time); //make Date objects
                if (dates[index].compareTo(minDate) < 0)           //establish origin
                {
                    minDate = dates[index];
                }
            } catch (ParseException e)
            {
                e.printStackTrace();
            }
            index++;
        }
    }

    public Long diffSeconds(Date d)
    {
        return (d.getTime() - minDate.getTime()) / 1000;
    }

    public static void main(String...args)
    {
        new Dater();
    }
}

输出:

1
0
2

答案 1 :(得分:1)

java.time

Answer by Saviour Self看起来是正确的。但它使用旧的日期时间类,这些类已被Java 8及更高版本中内置的java.time框架所取代。

Apache Commons CSV

作为奖励,我将展示如何使用Apache Commons CSV库来处理读取/写入CSV文件的繁琐工作。

首先,我们通过制作StringReader来模拟CSV文件。

RFC 4180规范

RFC 4180规范正式定义了CSV格式。对此的变化也存在。

RFC 4180要求回车 + 换行CRLF)作为换行符(行终止符)。最后一行的终结符是可选的,我们在这里包含它。

我们省略了可选的标题行(列标题)。

String newline = "\r\n";
StringBuilder input = new StringBuilder ();
input.append ( "2016-02-03,15:10:00,37" ).append ( newline );
input.append ( "2016-02-03,15:15:00,38" ).append ( newline );  // 5 minutes later.
input.append ( "2016-02-03,15:17:00,39" ).append ( newline );  // 2 minutes later.

Reader in = new StringReader ( input.toString () );

接下来,我们将整个CSV文件读入内存,其中Commons CSV库创建CSVRecord个对象来表示每行传入数据。一行代码完成所有工作,CSVFormat::parse生成CSVParser对象(Interable的实现)。

Iterable<CSVRecord> records;
try {
    records = CSVFormat.DEFAULT.parse ( in );  // 'records' is a CSVParser.
} catch ( IOException ex ) {
    // FIXME: Handle exception.
    System.out.println ( "[ERROR] " + ex );
    return; // Bail-out.
}

现在我们分析CSVRecord个对象的集合。记住第一个作为基线,在此存储为Instant(下面讨论)。然后循环以比较每个连续的CSVRecord对象,将每个字段检查为String

Instant firstInstant = null; // Track the baseline against which we calculate the increasing time
for ( CSVRecord record : records ) {
    String dateInput = record.get ( 0 );  // Zero-based index.
    String timeInput = record.get ( 1 );
    String priceInput = record.get ( 2 );
    //System.out.println ( dateInput + " | " + timeInput + " | " + priceInput );  // Dump input strings for debugging.

提取字符串仅限日期和时间,合并为LocalDateTime

    // Parse strings.
    LocalDate date = LocalDate.parse ( dateInput );
    LocalTime time = LocalTime.parse ( timeInput );
    Integer price = Integer.parseInt ( priceInput );
    // Combine date and time.
    LocalDateTime ldt = LocalDateTime.of ( date , time );  // Not a specific moment on the timeline.

此日期时间对象时间轴上的某个点,因为我们不知道其offset-from-UTC或时区。如果您要使用这些值来计算LocalDateTime个对象之间的差值,那么您将假设24小时的通用天数没有异常,例如夏令时(DST)。如果您的数据发生在任何异常情况下都不会发生,您可能会逃避这种情况,但这是一个坏习惯。如果已知,最好指定一个时区。

我们知道数据的来源,因此我们可以假定预期的时区ZoneId。通过分配假定的时区,我们可以在时间轴上获得真实的时刻。

    // Generally best to assign the time zone known to apply to this incoming data.
    ZoneId zoneId = ZoneId.of ( "America/New_York" );  // Move this line somewhere else to eliminate needless repetition.
    ZonedDateTime zdt = ldt.atZone ( zoneId );  // Now this becomes a specific moment on the timeline.

从那个ZonedDateTime我们可以用UTC(Instant)提取相同的时刻。通常,Instant是您应该用于数据存储,数据交换,序列化等的内容。您只需要ZonedDateTime在预期时区内向用户进行演示。

    Instant instant = zdt.toInstant ();  // Use Instant (moment on the timeline in UTC) for data storage, exchange, serialization, database, etc.
    if ( null == firstInstant ) {
        firstInstant = instant;  // Capture the first instant.
    }

目标是将每个CSVRecord与原始基线日期时间进行比较。 Duration.between方法就是这样做的。

    Duration duration = Duration.between ( firstInstant , instant );

我们计算总秒数的增量。

    Long deltaInSeconds = duration.getSeconds ();

将这些结果写入输出CSV文件留给读者练习。 Apache Commons CSV库的简短工作就是编写和读取CSV格式。

    // … output the deltaInSeconds & price to CSV. Apache Commons CSV can write as well as read CSV files.
    System.out.println ( "deltaInSeconds: " + deltaInSeconds + " | price: " + price );

}

跑步时。

deltaInSeconds: 0 | price: 37
deltaInSeconds: 300 | price: 38
deltaInSeconds: 420 | price: 39