diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..ca5f8a2
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
index faa46f2..8951330 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,3 +79,4 @@ com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
+/bin/
diff --git a/.project b/.project
new file mode 100644
index 0000000..d69bdc2
--- /dev/null
+++ b/.project
@@ -0,0 +1,23 @@
+
+
+ trading-backtest
+
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectbuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.buildship.core.gradleprojectnature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs
new file mode 100644
index 0000000..e889521
--- /dev/null
+++ b/.settings/org.eclipse.buildship.core.prefs
@@ -0,0 +1,2 @@
+connection.project.dir=
+eclipse.preferences.version=1
diff --git a/build.gradle b/build.gradle
index af28a9d..3cf58f8 100644
--- a/build.gradle
+++ b/build.gradle
@@ -25,6 +25,8 @@ dependencies {
compile 'org.slf4j:slf4j-api:1.7.+'
compile 'ch.qos.logback:logback-classic:1.+'
+
+ compile group: 'com.yahoofinance-api', name: 'YahooFinanceAPI', version: '3.13.0'
testCompile group: 'junit', name: 'junit', version: '4.11'
}
diff --git a/src/main/java/org/lst/trading/lib/util/HistoricalPriceService.java b/src/main/java/org/lst/trading/lib/util/HistoricalPriceService.java
index d6312d5..be405e8 100644
--- a/src/main/java/org/lst/trading/lib/util/HistoricalPriceService.java
+++ b/src/main/java/org/lst/trading/lib/util/HistoricalPriceService.java
@@ -1,8 +1,7 @@
package org.lst.trading.lib.util;
import org.lst.trading.lib.series.DoubleSeries;
-import rx.Observable;
public interface HistoricalPriceService {
- Observable getHistoricalAdjustedPrices(String symbol);
+ DoubleSeries getHistoricalAdjustedPrices(String symbol);
}
diff --git a/src/main/java/org/lst/trading/lib/util/yahoo/YahooFinance.java b/src/main/java/org/lst/trading/lib/util/yahoo/YahooFinance.java
deleted file mode 100755
index df61977..0000000
--- a/src/main/java/org/lst/trading/lib/util/yahoo/YahooFinance.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.lst.trading.lib.util.yahoo;
-
-import org.lst.trading.lib.csv.CsvReader;
-import org.lst.trading.lib.series.DoubleSeries;
-import org.lst.trading.lib.util.HistoricalPriceService;
-import org.lst.trading.lib.util.Http;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import rx.Observable;
-
-import java.time.Instant;
-import java.time.LocalDate;
-import java.time.OffsetDateTime;
-import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
-import java.util.stream.Stream;
-
-import static java.lang.String.format;
-import static org.lst.trading.lib.csv.CsvReader.ParseFunction.doubleColumn;
-import static org.lst.trading.lib.csv.CsvReader.ParseFunction.ofColumn;
-
-public class YahooFinance implements HistoricalPriceService {
- public static final String SEP = ",";
- public static final CsvReader.ParseFunction DATE_COLUMN = ofColumn("Date").map(s -> LocalDate.from(DateTimeFormatter.ISO_DATE.parse(s)).atStartOfDay(ZoneOffset.UTC.normalized()).toInstant());
- public static final CsvReader.ParseFunction CLOSE_COLUMN = doubleColumn("Close");
- public static final CsvReader.ParseFunction HIGH_COLUMN = doubleColumn("High");
- public static final CsvReader.ParseFunction LOW_COLUMN = doubleColumn("Low");
- public static final CsvReader.ParseFunction OPEN_COLUMN = doubleColumn("Open");
- public static final CsvReader.ParseFunction ADJ_COLUMN = doubleColumn("Adj Close");
- public static final CsvReader.ParseFunction VOLUME_COLUMN = doubleColumn("Volume");
- public static final OffsetDateTime DEFAULT_FROM = OffsetDateTime.of(2010, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC);
-
- private static final Logger log = LoggerFactory.getLogger(YahooFinance.class);
-
- @Override public Observable getHistoricalAdjustedPrices(String symbol) {
- return getHistoricalAdjustedPrices(symbol, DEFAULT_FROM.toInstant());
- }
-
- public Observable getHistoricalAdjustedPrices(String symbol, Instant from) {
- return getHistoricalAdjustedPrices(symbol, from, Instant.now());
- }
-
- public Observable getHistoricalAdjustedPrices(String symbol, Instant from, Instant to) {
- return getHistoricalPricesCsv(symbol, from, to).map(csv -> csvToDoubleSeries(csv, symbol));
- }
-
- private static Observable getHistoricalPricesCsv(String symbol, Instant from, Instant to) {
- return Http.get(createHistoricalPricesUrl(symbol, from, to))
- .flatMap(Http.asString());
- }
-
- private static DoubleSeries csvToDoubleSeries(String csv, String symbol) {
- Stream lines = Stream.of(csv.split("\n"));
- DoubleSeries prices = CsvReader.parse(lines, SEP, DATE_COLUMN, ADJ_COLUMN);
- prices.setName(symbol);
- prices = prices.toAscending();
- return prices;
- }
-
- private static String createHistoricalPricesUrl(String symbol, Instant from, Instant to) {
- return format("http://ichart.yahoo.com/table.csv?s=%s&%s&%s&g=d&ignore=.csv", symbol, toYahooQueryDate(from, "abc"), toYahooQueryDate(to, "def"));
- }
-
- private static String toYahooQueryDate(Instant instant, String names) {
- OffsetDateTime time = instant.atOffset(ZoneOffset.UTC);
- String[] strings = names.split("");
- return format("%s=%d&%s=%d&%s=%d", strings[0], time.getMonthValue() - 1, strings[1], time.getDayOfMonth(), strings[2], time.getYear());
- }
-}
diff --git a/src/main/java/org/lst/trading/lib/util/yahoo/YahooFinanceService.java b/src/main/java/org/lst/trading/lib/util/yahoo/YahooFinanceService.java
new file mode 100755
index 0000000..e111092
--- /dev/null
+++ b/src/main/java/org/lst/trading/lib/util/yahoo/YahooFinanceService.java
@@ -0,0 +1,68 @@
+package org.lst.trading.lib.util.yahoo;
+
+import java.io.FileNotFoundException;
+import java.math.BigDecimal;
+import java.net.SocketTimeoutException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+import org.lst.trading.lib.series.DoubleSeries;
+import org.lst.trading.lib.series.TimeSeries.Entry;
+import org.lst.trading.lib.util.HistoricalPriceService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import yahoofinance.Stock;
+import yahoofinance.YahooFinance;
+import yahoofinance.histquotes.HistoricalQuote;
+import yahoofinance.histquotes.Interval;
+
+public class YahooFinanceService implements HistoricalPriceService {
+
+ private static final Logger log = LoggerFactory.getLogger(YahooFinanceService.class);
+
+ private static final int DAYS_OF_HISTORY = 2520;
+
+ @Override
+ public DoubleSeries getHistoricalAdjustedPrices(String symbol) {
+ return getHistory(symbol, DAYS_OF_HISTORY);
+ }
+
+ public DoubleSeries getHistory(String symbol, int daysBack) {
+ DoubleSeries doubleSeries = new DoubleSeries(symbol);
+
+ try {
+ Calendar from = Calendar.getInstance();
+ from.add(Calendar.DAY_OF_MONTH, -daysBack);
+
+ Stock stock = YahooFinance.get(symbol);
+ //[n] is the most current, [0] is the last in history
+ List historicalQuotes = stock.getHistory(from, Interval.DAILY);
+
+ for (HistoricalQuote historicalQuote : historicalQuotes) {
+ BigDecimal open = historicalQuote.getOpen();
+ BigDecimal high = historicalQuote.getHigh();
+ BigDecimal low = historicalQuote.getLow();
+ BigDecimal close = historicalQuote.getClose();
+ BigDecimal adjClose = historicalQuote.getAdjClose();
+ Date time = historicalQuote.getDate().getTime();
+
+ if (open == null || high == null || low == null || close == null || adjClose == null) {
+ log.error(symbol + " " + time + " has missing data: " + open + ", " + high + ", " + low + ", " + close + ", " + adjClose);
+ continue;
+ }
+
+ doubleSeries.add(new Entry(adjClose.doubleValue(), time.toInstant()));
+ }
+ } catch (FileNotFoundException e) {
+ log.error("no such symbol: " + symbol);
+ } catch (SocketTimeoutException e) {
+ log.error("network error: " + symbol);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return doubleSeries;
+ }
+}
diff --git a/src/main/java/org/lst/trading/main/BacktestMain.java b/src/main/java/org/lst/trading/main/BacktestMain.java
index d4c124d..0b424c4 100644
--- a/src/main/java/org/lst/trading/main/BacktestMain.java
+++ b/src/main/java/org/lst/trading/main/BacktestMain.java
@@ -1,19 +1,19 @@
package org.lst.trading.main;
+import static java.lang.String.format;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Locale;
+
import org.lst.trading.lib.backtest.Backtest;
import org.lst.trading.lib.model.ClosedOrder;
import org.lst.trading.lib.model.TradingStrategy;
import org.lst.trading.lib.series.MultipleDoubleSeries;
import org.lst.trading.lib.util.Util;
-import org.lst.trading.lib.util.yahoo.YahooFinance;
+import org.lst.trading.lib.util.yahoo.YahooFinanceService;
import org.lst.trading.main.strategy.kalman.CointegrationTradingStrategy;
-import java.io.IOException;
-import java.net.URISyntaxException;
-import java.util.Locale;
-
-import static java.lang.String.format;
-
public class BacktestMain {
public static void main(String[] args) throws URISyntaxException, IOException {
String x = "GLD";
@@ -23,8 +23,8 @@ public static void main(String[] args) throws URISyntaxException, IOException {
TradingStrategy strategy = new CointegrationTradingStrategy(x, y);
// download historical prices
- YahooFinance finance = new YahooFinance();
- MultipleDoubleSeries priceSeries = new MultipleDoubleSeries(finance.getHistoricalAdjustedPrices(x).toBlocking().first(), finance.getHistoricalAdjustedPrices(y).toBlocking().first());
+ YahooFinanceService finance = new YahooFinanceService();
+ MultipleDoubleSeries priceSeries = new MultipleDoubleSeries(finance.getHistoricalAdjustedPrices(x), finance.getHistoricalAdjustedPrices(y));
// initialize the backtesting engine
int deposit = 15000;