В настоящее время я нахожусь на ранней стадии написания многогранного инвестиционного алгоритма. Часть, над которой я сейчас работаю, касается использования графической гауссовской модели со штрафом LASSO для поиска взаимозависимостей, которые можно использовать для информирования инвестиционной стратегии. В настоящее время я пытаюсь использовать JAVA для предварительной обработки ввода исторических данных CSV и создания нового выходного файла CSV с соответствующими данными.

Необработанные мелкомасштабные данные, которые я использую для тестирования алгоритма обработки (который в конечном итоге будет использоваться в прямой трансляции Reuters Eikon), находятся в формате txt / CSV. У меня есть папка, содержащая текстовые файлы с историческими данными по многим акциям NYSE. Хотя есть 8 столбцов, три, которые меня интересуют (для целей предварительной обработки перед созданием ковариационной матрицы, которая будет передаваться в GLASSO), - это дата, время и цены открытия. Столбец цен открытия не требует предварительной обработки, поэтому его можно передать в новый, менее шумный выходной файл.

Моя проблема в том, как преобразовать два столбца (дату и время) в одно измерение времени. Я думал, что наиболее очевидный способ сделать это - найти самый ранний момент времени в моих данных и использовать его как точку 0 (в секундах). Затем мне нужно будет преобразовать каждую комбинацию времени и даты в один столбец, показывающий, на сколько секунд прошло исходное время в выходном CSV-файле. Как только это будет сделано, а не указание пути к файлу, я хотел бы иметь возможность указать папку и цикл программы по всем текстовым файлам, находя соответствующие столбцы и выводя все в один файл CSV.

Как это, надеюсь, будет выглядеть на практике:

Название CSV и первая запись в одном текстовом файле NYSE -

"Дата, время, открытие, максимум, минимум, закрытие, объем, 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 секунд)

Чтобы повторить итерацию, input - это папка, содержащая сотни следующих форматированных CSV:

Столбцы - 1: Дата 2: Время 3: Открытие 4: Максимум 5: Минимум 6: Закрытие 7: Том 8: OpenInt

Результатом является один CSV-файл, содержащий:

Столбцы - 1: Измерение времени (расстояние в секундах от самой ранней точки входа) 2: Цена акции для каждой записи измерения времени.

Пожалуйста, дайте мне знать, если у вас есть какие-либо подсказки о том, как я могу это сделать, не стесняйтесь, дайте мне знать, если есть что-то, что я могу прояснить, чтобы облегчить вашу жизнь, я понимаю, что мог бы, возможно, объяснить это менее запутанная манера.

1
lel23 22 Фев 2016 в 20:21

2 ответа

Лучший ответ

Java.time

Ответ Спасителя выглядит правильным. Но он использует старые классы даты и времени, которые были вытеснены фреймворком java.time, встроенным в Java 8 и новее.

Apache Commons CSV

В качестве бонуса я покажу, как использовать библиотеку Apache Commons CSV для обработки рутинная работа по чтению / записи файлов CSV.

Сначала мы моделируем файл CSV, создавая {{X0 }}.

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). Вам может сойти с рук, если ваши данные случайно не появятся во время какой-либо аномалии, но это плохая привычка. Лучше назначить часовой пояс, если он известен.

Мы знаем источник данных, поэтому мы можем предположить предполагаемый часовой пояс, a 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
1
Community 23 Май 2017 в 10:28

Вот пример, использующий приведенную вами строку 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
2
Clark Kent 22 Фев 2016 в 18:36