// Copyright 2015 Ivan Popivanov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net.tradelib.core;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.xml.sax.HandlerBase;
public class TimeSeries<T> {
private ArrayList<LocalDateTime> index;
private ArrayList<ArrayList<T>> data;
// The names of the data columns
private HashMap<String, Integer> columnNames;
private T defaultValue;
public TimeSeries(int ncols) {
index = new ArrayList<LocalDateTime>();
data = new ArrayList<ArrayList<T>>();
for(int ii = 0; ii < ncols; ++ii) {
data.add(new ArrayList<T>());
}
columnNames = new HashMap<String, Integer>();
}
public TimeSeries(int ncols, int size) {
index = new ArrayList<LocalDateTime>();
data = new ArrayList<ArrayList<T>>();
for(int ii = 0; ii < ncols; ++ii) {
data.add(new ArrayList<T>(size));
}
columnNames = new HashMap<String, Integer>();
}
public TimeSeries() {
this(1);
}
public TimeSeries(String ...columnNames) {
this(columnNames.length);
setNames(columnNames);
}
public TimeSeries(TimeSeries<T> ts) {
index = new ArrayList<LocalDateTime>(ts.size());
index.addAll(ts.getTimestamps());
data = new ArrayList<ArrayList<T>>(ts.data.size());
for(int ii = 0; ii < ts.data.size(); ++ii) {
data.add(new ArrayList<T>(ts.data.get(ii)));
}
columnNames = new HashMap<String, Integer>();
columnNames.putAll(ts.columnNames);
}
public TimeSeries(ArrayList<LocalDateTime> ts, ArrayList<T> ...args) {
index = new ArrayList<LocalDateTime>(ts);
data = new ArrayList<ArrayList<T>>(args.length);
for(int ii = 0; ii < args.length; ++ii) {
data.add(args[ii]);
}
columnNames = new HashMap<String, Integer>();
}
public T get(int id) { return get(id, 0); }
public T get(int id, int colId) { return data.get(colId).get(id); }
public T get(int id, String colName) { return data.get(columnNames.get(colName)).get(id); }
public T get(LocalDateTime ts, int colId) {
int rowId = Collections.binarySearch(index, ts);
if(rowId < 0) {
throw new BadIndexException(ts.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " is not in the index");
}
return data.get(colId).get(rowId);
}
public T get(LocalDateTime ts, String colName) {
return get(ts, columnNames.get(colName));
}
public T get(String ts, int colId) {
return get(dateTimeFromString(ts), colId);
}
public T get(String ts, String colName) {
return get(ts, columnNames.get(colName));
}
public T get(String ts) {
return get(ts, 0);
}
public T getLast(int colId) {
return data.get(colId).get(index.size() - 1);
}
public T getLast(String colName) {
return getLast(columnNames.get(colName));
}
public T getLast() {
return getLast(0);
}
public T get(LocalDateTime ts) { return get(ts, 0); }
public TimeSeries<T> getData(int colId) {
return new TimeSeries<T>(index, data.get(colId));
}
public TimeSeries<T> columns(String colname) {
return getData(columnNames.get(colname));
}
public void set(int id, int colId, T tt) { data.get(colId).set(id, tt); }
public void set(int id, String colName, T tt) { set(id, columnNames.get(colName), tt); }
public void set(int id, T tt) { set(id, 0, tt); }
public void set(LocalDateTime ldt, int colId, T tt) {
int rowId = Collections.binarySearch(index, ldt);
if(rowId < 0) {
throw new BadIndexException(ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " is not in the index");
}
set(rowId, colId, tt);
}
public void set(LocalDateTime ldt, T tt) { set(ldt, 0, tt); }
public void add(LocalDateTime ts, T tt) {
if(index.size() > 0 && !ts.isAfter(index.get(index.size()-1))) {
throw new BadIndexException(ts.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " is not in chronological order " +
"last timestamp = " + index.get(index.size()-1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
index.add(ts);
for(int ii = 0; ii < data.size(); ++ii) {
data.get(ii).add(tt);
}
}
public void add(LocalDateTime ts, T ... args) {
if(index.size() > 0 && !ts.isAfter(index.get(index.size()-1))) {
throw new BadIndexException(ts.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " is not in chronological order " +
"last timestamp = " + index.get(index.size()-1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
index.add(ts);
for(int ii = 0; ii < data.size(); ++ii) {
if(ii < args.length) data.get(ii).add(args[ii]);
else data.get(ii).add(defaultValue);
}
}
public void addAll(List<LocalDateTime> ldts, T value) {
for(LocalDateTime ldt : ldts) {
add(ldt, value);
}
}
public int size() { return index.size(); }
public List<LocalDateTime> getTimestamps() { return index; }
// Returns the subList [0, end) - the "end" element is not included
public List<LocalDateTime> getTimestamps(int end) { return index.subList(0, end); }
// Returns the subList [beg, end) - the "end" element is not included
public List<LocalDateTime> getTimestamps(int beg, int end) { return index.subList(beg, end); }
public LocalDateTime getTimestamp(int id) { return index.get(id); }
public LocalDateTime getLastTimestamp() { return index.get(index.size() - 1); }
public TimeSeries<T> subset(LocalDateTime from, LocalDateTime to) {
int fromId = Collections.binarySearch(index, from);
if(fromId < 0) {
// The element is not in the list
fromId = Math.abs(fromId + 1);
}
int toId = Collections.binarySearch(index, to);
if(toId < 0) {
// The element is not in the list
toId = Math.abs(toId + 1);
}
TimeSeries<T> result = new TimeSeries<T>(data.size());
for(int row = fromId; row <= toId; ++row) {
result.index.add(index.get(row));
for(int col = 0; col < data.size(); ++col) {
result.data.get(col).add(data.get(col).get(row));
}
}
result.columnNames.putAll(columnNames);
return result;
}
private LocalDateTime dateTimeFromString(String str) {
LocalDateTime ldt = null;
try {
ldt = LocalDateTime.parse(str);
} catch(Exception e) {
ldt = null;
}
if(ldt == null) {
try {
ldt = LocalDate.parse(str).atStartOfDay();
} catch(Exception e) {
}
}
return ldt;
}
public void setNames(String ...names) {
columnNames.clear();
for(int ii = 0; ii < names.length; ++ii) {
columnNames.put(names[ii], ii);
}
}
public TimeSeries<T> subset(String from, String to) {
LocalDateTime ldtFrom = dateTimeFromString(from);
LocalDateTime ldtTo = ldtFrom != null ? dateTimeFromString(to) : null;
if(ldtTo == null || ldtFrom == null) return null;
return subset(ldtFrom, ldtTo);
}
public TimeSeries<T> subset(int year) {
TimeSeries<T> result = new TimeSeries<T>(data.size());
for(int row = 0; row <= size(); ++row) {
if(index.get(row).getYear() != year) continue;
result.index.add(index.get(row));
for(int col = 0; col < data.size(); ++col) {
result.data.get(col).add(data.get(col).get(row));
}
}
result.columnNames.putAll(columnNames);
return result;
}
}