diff --git a/.gitignore b/.gitignore index e65879e..af2bd83 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf +.idea/**/misc.xml +.settings # Generated files .idea/**/contentModel.xml @@ -125,4 +127,9 @@ gradle-app.setting ### Gradle Patch ### **/build/ +.project +.classpath +gradlew +gradlew.bat +gradle # End of https://www.gitignore.io/api/java,gradle,intellij \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..8613f56 --- /dev/null +++ b/build.gradle @@ -0,0 +1,18 @@ +plugins { + id 'java' +} + +group 'crazzyghost' +version '1.0-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.12' + implementation 'com.squareup.okhttp3:okhttp:3.11.0' + implementation 'com.squareup.moshi:moshi:1.8.0' +} diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e5e0481 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'alphavantage' + diff --git a/src/main/java/com/crazzyghost/alphavantage/AlphaVantage.java b/src/main/java/com/crazzyghost/alphavantage/AlphaVantage.java new file mode 100644 index 0000000..f4f667a --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/AlphaVantage.java @@ -0,0 +1,51 @@ +package com.crazzyghost.alphavantage; + +import com.crazzyghost.alphavantage.exchangerate.ExchangeRate; +import com.crazzyghost.alphavantage.forex.Forex; +import com.crazzyghost.alphavantage.timeseries.TimeSeries; + +public class AlphaVantage { + + private static AlphaVantage INSTANCE; + private Config config; + private TimeSeries timeSeries; + private Forex forex; + private ExchangeRate exchangeRate; + + private AlphaVantage(Config config){ + this.config = config; + } + + public static void init(Config config){ + INSTANCE = new AlphaVantage(config); + } + + public static AlphaVantage api(){ + if(INSTANCE == null){ + throw new AlphaVantageException("Call AlphaVantage.init"); + } + return INSTANCE; + } + + public TimeSeries timeSeries(){ + if(timeSeries == null){ + timeSeries = new TimeSeries(config); + } + return timeSeries; + } + + public Forex forex(){ + if(forex == null){ + forex = new Forex(config); + } + return forex; + } + + + public ExchangeRate exchangeRate() { + if(exchangeRate == null){ + exchangeRate = new ExchangeRate(config); + } + return exchangeRate; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/AlphaVantageException.java b/src/main/java/com/crazzyghost/alphavantage/AlphaVantageException.java new file mode 100644 index 0000000..e178d29 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/AlphaVantageException.java @@ -0,0 +1,13 @@ +package com.crazzyghost.alphavantage; + +public class AlphaVantageException extends RuntimeException{ + + public AlphaVantageException(){ + super(); + } + + public AlphaVantageException(String msg){ + super(msg); + } + +} diff --git a/src/main/java/com/crazzyghost/alphavantage/Config.java b/src/main/java/com/crazzyghost/alphavantage/Config.java new file mode 100644 index 0000000..324b5b0 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/Config.java @@ -0,0 +1,44 @@ +package com.crazzyghost.alphavantage; + +public class Config { + + private String key; + private int timeOut; + public static String BASE_URL = "https://www.alphavantage.co/query?"; + + public Config(Builder builder) { + this.key = builder.key; + this.timeOut = builder.timeOut; + } + + public int getTimeOut() { + return timeOut; + } + + public String getKey() { + return key; + } + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder{ + private String key; + private int timeOut; + + public Builder key(String key){ + this.key = key; + return this; + } + + public Builder timeOut(int timeOut){ + this.timeOut = timeOut; + return this; + } + + public Config build(){ + return new Config(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/Fetcher.java b/src/main/java/com/crazzyghost/alphavantage/Fetcher.java new file mode 100644 index 0000000..210bf09 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/Fetcher.java @@ -0,0 +1,14 @@ +package com.crazzyghost.alphavantage; + +public interface Fetcher{ + + void fetch(); + + interface SuccessCallback{ + void onSuccess(V response); + } + + interface FailureCallback{ + void onFailure(AlphaVantageException ex); + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/Main.java b/src/main/java/com/crazzyghost/alphavantage/Main.java new file mode 100644 index 0000000..60b5eac --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/Main.java @@ -0,0 +1,34 @@ +package com.crazzyghost.alphavantage; + + +import com.crazzyghost.alphavantage.parameters.DataType; +import com.crazzyghost.alphavantage.parameters.Interval; + +public class Main { + + + + public static void main(String[] args){ + + + Config config = Config.builder() + .key("M77PQNYAVBG0MB5N") + .timeOut(5) + .build(); + + AlphaVantage.init(config); + + + AlphaVantage.api() + .timeSeries() + .monthly() + .onFailure(System.out::println) + .adjusted() + .onSuccess(System.out::println) + .forSymbol("AAPL") + .fetch(); + + } + + +} diff --git a/src/main/java/com/crazzyghost/alphavantage/UrlExtractor.java b/src/main/java/com/crazzyghost/alphavantage/UrlExtractor.java new file mode 100644 index 0000000..d53a4e5 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/UrlExtractor.java @@ -0,0 +1,39 @@ +package com.crazzyghost.alphavantage; + +import java.lang.reflect.Field; + + +public class UrlExtractor{ + + public static String extract(Object object){ + + StringBuilder stringBuilder = new StringBuilder(); + + Class cls = object.getClass(); + while(cls != null){ + Field[] fields = cls.getDeclaredFields(); + for(Field field : fields){ + field.setAccessible(true); + try { + + if (field.get(object) != null){ + stringBuilder.append(field.getName()) + .append("="); + if(field.getType().isEnum()){ + String value = (field.get(object)).toString(); + stringBuilder.append(value).append("&"); + }else{ + stringBuilder.append((String)field.get(object)).append("&"); + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + cls = cls.getSuperclass(); + } + + return stringBuilder.append("apikey=").toString(); + + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRate.java b/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRate.java new file mode 100644 index 0000000..d4f50b6 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRate.java @@ -0,0 +1,123 @@ +package com.crazzyghost.alphavantage.exchangerate; + +import com.crazzyghost.alphavantage.AlphaVantageException; +import com.crazzyghost.alphavantage.Fetcher; +import com.crazzyghost.alphavantage.Config; +import com.crazzyghost.alphavantage.UrlExtractor; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.squareup.moshi.Types; +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class ExchangeRate implements Fetcher { + + private Config config; + private ExchangeRateRequest request; + private ExchangeRateRequest.Builder builder; + private Fetcher.SuccessCallback successCallback; + private Fetcher.FailureCallback failureCallback; + + public ExchangeRate(Config config){ + this.config = config; + this.request = null; + this.builder = ExchangeRateRequest.builder(); + } + + public ExchangeRate toCurrency(String toCurrency){ + this.builder.toCurrency(toCurrency); + return this; + } + + public ExchangeRate fromCurrency(String fromCurrency){ + this.builder.fromCurrency(fromCurrency); + return this; + } + + /** + * @param callback successful fetch handler + * @return current instance of {@link ExchangeRateResponse} + */ + public ExchangeRate onSuccess(SuccessCallback callback){ + this.successCallback = callback; + return this; + } + + /** + * @param callback failed fetch handler + * @return current instance of {@link ExchangeRateResponse} + */ + public ExchangeRate onFailure(FailureCallback callback){ + this.failureCallback = callback; + return this; + } + + @Override + public void fetch() { + + //make sure the key is set + if(config.getKey() == null){ + throw new AlphaVantageException("Config not set"); + } + //build the api request parameters object finally + this.request = this.builder.build(); + //okhttp + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(config.getTimeOut(), TimeUnit.SECONDS) + .build(); + + Request request = new Request.Builder() + .url(Config.BASE_URL + UrlExtractor.extract(this.request) + config.getKey()) + .build(); + + System.out.println(Config.BASE_URL + UrlExtractor.extract(this.request) + config.getKey()); + + //make the call + System.out.println("Fetching Response ..."); + client.newCall(request).enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Call call, IOException e) { + //respond to callback on failure + System.out.println("Failed Fetching Response ... " + e.getClass().getCanonicalName()); + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException()); + } + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + System.out.println("Received Response."); + if(response.isSuccessful()){ + + Moshi moshi = new Moshi.Builder().build(); + Type type = Types.newParameterizedType(Map.class, String.class, Object.class); + JsonAdapter> adapter = moshi.adapter(type); + ExchangeRateResponse exchangeResponse = ExchangeRateResponse.of(adapter.fromJson(response.body().string())); + if(exchangeResponse.getErrorMessage() != null){ + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException(exchangeResponse.getErrorMessage())); + } + System.err.println(exchangeResponse.getErrorMessage()); + return; + } + if(successCallback != null) + successCallback.onSuccess(exchangeResponse); + System.out.println("Success Fetching Response!"); + }else{ + + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException()); + } + System.err.println("Error Fetching Response."); + } + } + }); + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRateRequest.java b/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRateRequest.java new file mode 100644 index 0000000..b19ca56 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRateRequest.java @@ -0,0 +1,47 @@ +package com.crazzyghost.alphavantage.exchangerate; + +import com.crazzyghost.alphavantage.parameters.Function; + +public class ExchangeRateRequest { + + + private Function function; + private String from_currency; + private String to_currency; + + + private ExchangeRateRequest(Builder builder){ + this.function = builder.function; + this.from_currency = builder.fromCurrency; + this.to_currency = builder.toCurrency; + } + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder{ + Function function; + String fromCurrency; + String toCurrency; + + public Builder(){ + this.function = Function.CURRENCY_EXCHANGE_RATE; + } + + public Builder fromCurrency(String fromCurrency){ + this.fromCurrency = fromCurrency; + return this; + } + + public Builder toCurrency(String toCurrency){ + this.toCurrency = toCurrency; + return this; + } + + public ExchangeRateRequest build(){ + return new ExchangeRateRequest(this); + } + + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRateResponse.java b/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRateResponse.java new file mode 100644 index 0000000..5701f4a --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/exchangerate/ExchangeRateResponse.java @@ -0,0 +1,96 @@ +package com.crazzyghost.alphavantage.exchangerate; + +import com.crazzyghost.alphavantage.AlphaVantageException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ExchangeRateResponse { + + private String fromCurrencyCode; + private String fromCurrencyName; + private String toCurrencyCode; + private String toCurrencyName; + private Double exchangeRate; + private String lastRefreshed; + private String timeZone; + + private String errorMessage; + + private ExchangeRateResponse( + String fromCurrencyCode, + String fromCurrencyName, + String toCurrencyCode, + String toCurrencyName, + Double exchangeRate, + String lastRefreshed, + String timeZone) { + this.fromCurrencyCode = fromCurrencyCode; + this.fromCurrencyName = fromCurrencyName; + this.toCurrencyCode = toCurrencyCode; + this.toCurrencyName = toCurrencyName; + this.exchangeRate = exchangeRate; + this.lastRefreshed = lastRefreshed; + this.timeZone = timeZone; + this.errorMessage = null; + } + + private ExchangeRateResponse(String errorMessage){ + this.errorMessage = errorMessage; + } + + public static ExchangeRateResponse of(Map stringObjectMap){ + Parser parser = new Parser(); + return parser.parse(stringObjectMap); + } + + public String getErrorMessage() { + return errorMessage; + } + + public static class Parser { + + + ExchangeRateResponse parse(Map stringObjectMap) { + + //get the keys + List keys = new ArrayList<>(stringObjectMap.keySet()); + + Map md; + + try{ + md = (Map) stringObjectMap.get(keys.get(0)); + + }catch (ClassCastException e){ + return new ExchangeRateResponse((String)stringObjectMap.get(keys.get(0))); + } + + + return new ExchangeRateResponse( + md.get("1. From_Currency Code"), + md.get("2. From_Currency Name"), + md.get("3. To_Currency Code"), + md.get("4. To_Currency Name"), + Double.parseDouble(md.get("5. Exchange Rate")), + md.get("6. Last Refreshed"), + md.get("7. Time Zone") + ); + + } + } + + @Override + public String toString() { + return "ExchangeRateResponse{" + + "fromCurrencyCode='" + fromCurrencyCode + '\'' + + ", fromCurrencyName='" + fromCurrencyName + '\'' + + ", toCurrencyCode='" + toCurrencyCode + '\'' + + ", toCurrencyName='" + toCurrencyName + '\'' + + ", exchangeRate=" + exchangeRate + + ", lastRefreshed='" + lastRefreshed + '\'' + + ", timeZone='" + timeZone + '\'' + + ", errorMessage='" + errorMessage + '\'' + + '}'; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/Forex.java b/src/main/java/com/crazzyghost/alphavantage/forex/Forex.java new file mode 100644 index 0000000..ac6fd09 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/Forex.java @@ -0,0 +1,214 @@ +package com.crazzyghost.alphavantage.forex; + +import com.crazzyghost.alphavantage.AlphaVantageException; +import com.crazzyghost.alphavantage.Fetcher; +import com.crazzyghost.alphavantage.Config; +import com.crazzyghost.alphavantage.UrlExtractor; +import com.crazzyghost.alphavantage.forex.request.*; +import com.crazzyghost.alphavantage.forex.response.ForexResponse; +import com.crazzyghost.alphavantage.parameters.DataType; +import com.crazzyghost.alphavantage.parameters.Interval; +import com.crazzyghost.alphavantage.parameters.OutputSize; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.squareup.moshi.Types; +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class Forex{ + + + + private Config config; + private ForexRequest request; + private ForexRequest.Builder builder; + private Fetcher.SuccessCallback successCallback; + private Fetcher.FailureCallback failureCallback; + + + public Forex(Config config){ + this.config = config; + request = null; + } + + public WeeklyRequestHelper weekly(){ + return new WeeklyRequestHelper(); + } + + public DailyRequestHelper daily(){ + return new DailyRequestHelper(); + } + + public IntraDayRequestHelper intraday(){ + return new IntraDayRequestHelper(); + } + + public MonthlyRequestHelper monthly(){ + return new MonthlyRequestHelper(); + } + + + private void fetch(){ + + //make sure the key is set + if(config.getKey() == null){ + throw new AlphaVantageException("Config not set"); + } + //build the api request parameters object finally + this.request = this.builder.build(); + //okhttp + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(config.getTimeOut(), TimeUnit.SECONDS) + .build(); + + Request request = new Request.Builder() + .url(Config.BASE_URL + UrlExtractor.extract(this.request) + config.getKey()) + .build(); + + System.out.println(Config.BASE_URL + UrlExtractor.extract(this.request) + config.getKey()); + + //make the call + System.out.println("Fetching Response ..."); + client.newCall(request).enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Call call, IOException e) { + //respond to callback on failure + System.out.println("Failed Fetching Response ... " + e.getClass().getCanonicalName()); +// + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException()); + } + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + System.out.println("Received Response."); + if(response.isSuccessful()){ + + Moshi moshi = new Moshi.Builder().build(); + Type type = Types.newParameterizedType(Map.class, String.class, Object.class); + JsonAdapter> adapter = moshi.adapter(type); + ForexResponse forexResponse = ForexResponse.of(adapter.fromJson(response.body().string())); + + if(forexResponse.getErrorMessage() != null) { + if(failureCallback != null) + failureCallback.onFailure(new AlphaVantageException(forexResponse.getErrorMessage())); + System.err.println("Error Fetching Response."); + return; + } + if(successCallback != null){ + successCallback.onSuccess(forexResponse); + System.out.println("Success Fetching Response!"); + } + }else{ + + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException()); + } + System.err.println("Error Fetching Response"); + } + } + }); + } + + + public abstract class RequestHelper implements Fetcher { + + protected ForexRequest.Builder builder; + + private RequestHelper(){ + + } + + public T toSymbol(String toSymbol){ + this.builder.toSymbol(toSymbol); + return (T)this; + } + + public T fromSymbol(String fromSymbol){ + this.builder.fromSymbol(fromSymbol); + return (T)this; + } + + public T dataType(DataType type){ + this.builder.dataType(type); + return (T)this; + } + + + public T onSuccess(SuccessCallback callback) { + Forex.this.successCallback = callback; + return (T)this; + } + + + public T onFailure(FailureCallback callback) { + Forex.this.failureCallback = callback; + return (T)this; + } + + @Override + public void fetch() { + Forex.this.builder = this.builder; + Forex.this.fetch(); + } + + } + + + public class DailyRequestHelper extends RequestHelper{ + + DailyRequestHelper() { + super(); + this.builder = DailyRequest.builder(); + } + + public DailyRequestHelper outputSize(OutputSize size){ + ((DailyRequest.Builder)this.builder).outputSize(size); + return this; + } + + } + + public class IntraDayRequestHelper extends RequestHelper{ + + IntraDayRequestHelper() { + super(); + this.builder = IntraDayRequest.builder(); + } + + public IntraDayRequestHelper outputSize(OutputSize size){ + ((DailyRequest.Builder)this.builder).outputSize(size); + return this; + } + + public IntraDayRequestHelper interval(Interval interval){ + ((IntraDayRequest.Builder)this.builder).interval(interval); + return this; + } + } + + public class WeeklyRequestHelper extends RequestHelper{ + + WeeklyRequestHelper(){ + super(); + this.builder = WeeklyRequest.builder(); + System.out.println(this.builder); + } + } + + public class MonthlyRequestHelper extends RequestHelper{ + + MonthlyRequestHelper(){ + super(); + this.builder = MonthlyRequest.builder(); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/request/DailyRequest.java b/src/main/java/com/crazzyghost/alphavantage/forex/request/DailyRequest.java new file mode 100644 index 0000000..3f545a1 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/request/DailyRequest.java @@ -0,0 +1,42 @@ +package com.crazzyghost.alphavantage.forex.request; + +import com.crazzyghost.alphavantage.parameters.Function; +import com.crazzyghost.alphavantage.parameters.OutputSize; + +public class DailyRequest extends ForexRequest{ + + private Function function; + private OutputSize outputSize; + + private DailyRequest(Builder builder){ + super(builder); + this.function = Function.FX_DAILY; + this.outputSize = builder.outputSize != null ? builder.outputSize : OutputSize.COMPACT; + } + + public static Builder builder() { + return new Builder(); + } + + + public static class Builder extends ForexRequest.Builder{ + + Function function; + OutputSize outputSize; + + public Builder function(Function function){ + this.function = function; + return this; + } + + public Builder outputSize(OutputSize outputSize){ + this.outputSize = outputSize; + return this; + } + + @Override + public ForexRequest build() { + return new DailyRequest(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/request/ForexRequest.java b/src/main/java/com/crazzyghost/alphavantage/forex/request/ForexRequest.java new file mode 100644 index 0000000..99c4ee6 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/request/ForexRequest.java @@ -0,0 +1,43 @@ +package com.crazzyghost.alphavantage.forex.request; + +import com.crazzyghost.alphavantage.parameters.DataType; + +public abstract class ForexRequest{ + + protected String from_symbol; + protected String to_symbol; + protected DataType dataType; + + protected ForexRequest(Builder builder) { + this.to_symbol = builder.toSymbol; + this.from_symbol = builder.fromSymbol; + this.dataType = builder.dataType != null ? builder.dataType : DataType.JSON ; + } + + + public abstract static class Builder { + + public String fromSymbol; + public String toSymbol; + public DataType dataType; + + public T fromSymbol(String fromSymbol){ + this.fromSymbol = fromSymbol; + return (T) this; + } + + public T toSymbol(String fromSymbol){ + this.toSymbol =fromSymbol; + return (T) this; + } + + public T dataType(DataType dataType){ + this.dataType = dataType; + return (T) this; + } + + + public abstract ForexRequest build(); + + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/request/IntraDayRequest.java b/src/main/java/com/crazzyghost/alphavantage/forex/request/IntraDayRequest.java new file mode 100644 index 0000000..35fe0ca --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/request/IntraDayRequest.java @@ -0,0 +1,45 @@ +package com.crazzyghost.alphavantage.forex.request; + +import com.crazzyghost.alphavantage.parameters.Function; +import com.crazzyghost.alphavantage.parameters.Interval; +import com.crazzyghost.alphavantage.parameters.OutputSize; + +public class IntraDayRequest extends ForexRequest { + + private Interval interval; + private Function function; + private OutputSize outputSize; + + private IntraDayRequest(Builder builder){ + super(builder); + this.function = Function.FX_INTRADAY; + this.outputSize = builder.outputSize != null ? builder.outputSize : OutputSize.COMPACT; + this.interval = builder.interval != null ? builder.interval : Interval.ONE_MIN; + } + + + public static Builder builder() { + return new Builder(); + } + + public static class Builder extends ForexRequest.Builder{ + + Interval interval; + OutputSize outputSize; + + public Builder interval(Interval interval){ + this.interval = interval; + return this; + } + + public Builder outputSize(OutputSize outputSize){ + this.outputSize = outputSize; + return this; + } + + @Override + public IntraDayRequest build() { + return new IntraDayRequest(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/request/MonthlyRequest.java b/src/main/java/com/crazzyghost/alphavantage/forex/request/MonthlyRequest.java new file mode 100644 index 0000000..18b70bd --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/request/MonthlyRequest.java @@ -0,0 +1,30 @@ +package com.crazzyghost.alphavantage.forex.request; + +import com.crazzyghost.alphavantage.parameters.Function; + +public class MonthlyRequest extends ForexRequest{ + + private Function function; + + private MonthlyRequest(Builder builder){ + super(builder); + this.function = Function.FX_MONTHLY; + } + + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder extends ForexRequest.Builder { + + public Builder(){ + super(); + } + + @Override + public MonthlyRequest build() { + return new MonthlyRequest(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/request/WeeklyRequest.java b/src/main/java/com/crazzyghost/alphavantage/forex/request/WeeklyRequest.java new file mode 100644 index 0000000..b399a98 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/request/WeeklyRequest.java @@ -0,0 +1,30 @@ +package com.crazzyghost.alphavantage.forex.request; + +import com.crazzyghost.alphavantage.parameters.Function; + +public class WeeklyRequest extends ForexRequest{ + + private Function function; + + private WeeklyRequest(Builder builder){ + super(builder); + this.function = Function.FX_WEEKLY; + } + + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder extends ForexRequest.Builder { + + public Builder(){ + super(); + } + + @Override + public WeeklyRequest build() { + return new WeeklyRequest(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/response/ForexResponse.java b/src/main/java/com/crazzyghost/alphavantage/forex/response/ForexResponse.java new file mode 100644 index 0000000..e6a8f4c --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/response/ForexResponse.java @@ -0,0 +1,110 @@ +package com.crazzyghost.alphavantage.forex.response; + +import com.crazzyghost.alphavantage.AlphaVantageException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ForexResponse { + + + private MetaData metaData; + private List forexUnits; + private String errorMessage; + + private ForexResponse(MetaData metaData, List forexUnits) { + this.metaData = metaData; + this.forexUnits = forexUnits; + this.errorMessage = null; + } + + private ForexResponse(String errorMessage){ + this.metaData = MetaData.empty(); + this.forexUnits = new ArrayList<>(); + this.errorMessage = errorMessage; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public MetaData getMetaData() { + return metaData; + } + + public void setMetaData(MetaData metaData) { + this.metaData = metaData; + } + + public List getForexUnits() { + return forexUnits; + } + + public void setForexUnits(List forexUnits) { + this.forexUnits = forexUnits; + } + + public static ForexResponse of(Map stringObjectMap){ + Parser parser = new Parser(); + return parser.parse(stringObjectMap); + } + + public static class Parser { + + + ForexResponse parse(Map stringObjectMap) { + + //get the keys + List keys = new ArrayList<>(stringObjectMap.keySet()); + + Map md; + Map> stockData; + + try{ + md = (Map) stringObjectMap.get(keys.get(0)); + stockData = (Map>) stringObjectMap.get(keys.get(1)); + + }catch (ClassCastException e){ + return new ForexResponse((String)stringObjectMap.get(keys.get(0))); + } + + + MetaData metaData = new MetaData( + md.get("1. Information"), + md.get("2. From Symbol"), + md.get("3. To Symbol"), + md.get("4. Last Refreshed"), + md.get("5. Interval"), + md.get("6. Output Size"), + md.get("7. Time Zone") + ); + + List forexUnits = new ArrayList<>(); + + for (Map m: stockData.values()) { + ForexUnit.Builder stockUnit = ForexUnit.builder(); + stockUnit.open(Double.parseDouble(m.get("1. open"))); + stockUnit.high(Double.parseDouble(m.get("2. high"))); + stockUnit.low(Double.parseDouble(m.get("3. low"))); + stockUnit.close(Double.parseDouble(m.get("4. close"))); + forexUnits.add(stockUnit.build()); + } + return new ForexResponse(metaData, forexUnits); + } + } + + + @Override + public String toString() { + return "ForexResponse{" + + "metaData=" + metaData + + ", forexUnits=" + forexUnits.size() + + ", errorMessage='" + errorMessage + '\'' + + '}'; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/response/ForexUnit.java b/src/main/java/com/crazzyghost/alphavantage/forex/response/ForexUnit.java new file mode 100644 index 0000000..19fa21e --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/response/ForexUnit.java @@ -0,0 +1,62 @@ +package com.crazzyghost.alphavantage.forex.response; + +public class ForexUnit { + + private double open; + private double high; + private double low; + private double close; + + private ForexUnit(Builder builder) { + this.open = builder.open; + this.high = builder.high; + this.low = builder.low; + this.close = builder.close; + } + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder{ + + double open; + double high; + double low; + double close; + + public Builder open(double open){ + this.open = open; + return this; + } + + public Builder high(double high){ + this.high = open; + return this; + } + public Builder low(double low){ + this.low = low; + return this; + } + + public Builder close(double close){ + this.close = low; + return this; + } + + public ForexUnit build(){ + return new ForexUnit(this); + } + + } + + @Override + public String toString() { + return "ForexUnit{" + + "open=" + open + + ", high=" + high + + ", low=" + low + + ", close=" + close + + '}'; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/forex/response/MetaData.java b/src/main/java/com/crazzyghost/alphavantage/forex/response/MetaData.java new file mode 100644 index 0000000..bd11a9d --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/forex/response/MetaData.java @@ -0,0 +1,103 @@ +package com.crazzyghost.alphavantage.forex.response; + +public class MetaData { + + private String information; + private String fromSymbol; + private String toSymbol; + private String lastRefreshed; + private String interval; + private String outputSize; + private String timeZone; + + + public MetaData( + String information, + String fromSymbol, + String toSymbol, + String lastRefreshed, + String interval, + String outputSize, + String timeZone) { + this.information = information; + this.fromSymbol = fromSymbol; + this.toSymbol = toSymbol; + this.lastRefreshed = lastRefreshed; + this.interval = interval; + this.outputSize = outputSize; + this.timeZone = timeZone; + } + + public static MetaData empty(){ + return new MetaData("","","","","","",""); + } + + public String getInformation() { + return information; + } + + public void setInformation(String information) { + this.information = information; + } + + public String getFromSymbol() { + return fromSymbol; + } + + public void setFromSymbol(String fromSymbol) { + this.fromSymbol = fromSymbol; + } + + public String getToSymbol() { + return toSymbol; + } + + public void setToSymbol(String toSymbol) { + this.toSymbol = toSymbol; + } + + public String getLastRefreshed() { + return lastRefreshed; + } + + public void setLastRefreshed(String lastRefreshed) { + this.lastRefreshed = lastRefreshed; + } + + public String getInterval() { + return interval; + } + + public void setInterval(String interval) { + this.interval = interval; + } + + public String getOutputSize() { + return outputSize; + } + + public void setOutputSize(String outputSize) { + this.outputSize = outputSize; + } + + public String getTimeZone() { + return timeZone; + } + + public void setTimeZone(String timeZone) { + this.timeZone = timeZone; + } + + @Override + public String toString() { + return "MetaData{" + + "information='" + information + '\'' + + ", fromSymbol='" + fromSymbol + '\'' + + ", toSymbol='" + toSymbol + '\'' + + ", lastRefreshed='" + lastRefreshed + '\'' + + ", interval='" + interval + '\'' + + ", outputSize='" + outputSize + '\'' + + ", timeZone='" + timeZone + '\'' + + '}'; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/parameters/DataType.java b/src/main/java/com/crazzyghost/alphavantage/parameters/DataType.java new file mode 100644 index 0000000..3f9281b --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/parameters/DataType.java @@ -0,0 +1,18 @@ +package com.crazzyghost.alphavantage.parameters; + +public enum DataType { + + JSON("json"), + CSV("csv"); + + private String dataType; + + DataType(String dataType){ + this.dataType = dataType; + } + + @Override + public String toString() { + return dataType; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/parameters/Function.java b/src/main/java/com/crazzyghost/alphavantage/parameters/Function.java new file mode 100644 index 0000000..f2816b8 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/parameters/Function.java @@ -0,0 +1,21 @@ +package com.crazzyghost.alphavantage.parameters; + +public enum Function { + + //Stock Time Series Functions + TIME_SERIES_INTRADAY, + TIME_SERIES_DAILY, + TIME_SERIES_DAILY_ADJUSTED, + TIME_SERIES_WEEKLY, + TIME_SERIES_WEEKLY_ADJUSTED, + TIME_SERIES_MONTHLY, + TIME_SERIES_MONTHLY_ADJUSTED, + //Forex (FX) Functions + CURRENCY_EXCHANGE_RATE, + FX_INTRADAY, + FX_DAILY, + FX_WEEKLY, + FX_MONTHLY, + + +} diff --git a/src/main/java/com/crazzyghost/alphavantage/parameters/Interval.java b/src/main/java/com/crazzyghost/alphavantage/parameters/Interval.java new file mode 100644 index 0000000..35b1121 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/parameters/Interval.java @@ -0,0 +1,23 @@ +package com.crazzyghost.alphavantage.parameters; + +public enum Interval { + + + ONE_MIN("1min"), + FIVE_MIN("5min") , + FIFTEEN_MIN("15min"), + THIRTY_MIN("30min"), + SIXTY_MIN("60min"); + + private String interval; + + Interval(String interval){ + this.interval = interval; + } + + + @Override + public String toString() { + return this.interval; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/parameters/OutputSize.java b/src/main/java/com/crazzyghost/alphavantage/parameters/OutputSize.java new file mode 100644 index 0000000..43e8fbc --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/parameters/OutputSize.java @@ -0,0 +1,18 @@ +package com.crazzyghost.alphavantage.parameters; + +public enum OutputSize { + + COMPACT("compact"), + FULL("full"); + + private String outputSize; + + OutputSize(String outputSize){ + this.outputSize = outputSize; + } + + @Override + public String toString() { + return this.outputSize; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/TimeSeries.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/TimeSeries.java new file mode 100644 index 0000000..1184c79 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/TimeSeries.java @@ -0,0 +1,227 @@ +package com.crazzyghost.alphavantage.timeseries; + +import com.crazzyghost.alphavantage.AlphaVantageException; +import com.crazzyghost.alphavantage.Config; +import com.crazzyghost.alphavantage.Fetcher; +import com.crazzyghost.alphavantage.UrlExtractor; +import com.crazzyghost.alphavantage.parameters.DataType; +import com.crazzyghost.alphavantage.parameters.Interval; +import com.crazzyghost.alphavantage.parameters.OutputSize; +import com.crazzyghost.alphavantage.timeseries.request.*; +import com.crazzyghost.alphavantage.timeseries.response.TimeSeriesResponse; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; +import com.squareup.moshi.Types; +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class TimeSeries{ + + private Config config; + private TimeSeriesRequest request; + private TimeSeriesRequest.Builder builder; + private boolean adjusted = false; + private Fetcher.SuccessCallback successCallback; + private Fetcher.FailureCallback failureCallback; + + public TimeSeries(Config config){ + this.config = config; + request = null; + } + + + public MonthlyRequestHelper monthly(){ + this.adjusted = false; + return new MonthlyRequestHelper(); + } + + public WeeklyRequestHelper weekly(){ + this.adjusted = false; + return new WeeklyRequestHelper(); + } + + public DailyRequestHelper daily(){ + this.adjusted = false; + return new DailyRequestHelper(); + } + + public IntraDayRequestHelper intraday(){ + this.adjusted = false; + return new IntraDayRequestHelper(); + } + + + public void fetch(){ + + //make sure the key is set + if(config.getKey() == null){ + throw new AlphaVantageException("Config not set"); + } + //build the api request parameters object finally + this.request = this.builder.build(); + //okhttp + OkHttpClient client = new OkHttpClient.Builder() + .connectTimeout(config.getTimeOut(), TimeUnit.SECONDS) + .build(); + + Request request = new Request.Builder() + .url(Config.BASE_URL + UrlExtractor.extract(this.request) + config.getKey()) + .build(); + + System.out.println(Config.BASE_URL + UrlExtractor.extract(this.request) + config.getKey()); + + //make the call + System.out.println("Fetching Response ..."); + client.newCall(request).enqueue(new okhttp3.Callback() { + @Override + public void onFailure(Call call, IOException e) { + //respond to callback on failure + System.out.println("Failed Fetching Response ... " + e.getClass().getCanonicalName()); + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException()); + } + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + System.out.println("Received Response."); + if(response.isSuccessful()){ + + Moshi moshi = new Moshi.Builder().build(); + Type type = Types.newParameterizedType(Map.class, String.class, Object.class); + JsonAdapter> adapter = moshi.adapter(type); + TimeSeriesResponse stockResponse = TimeSeriesResponse.of(adapter.fromJson(response.body().string()), adjusted); + if(stockResponse.getErrorMessage() != null){ + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException(stockResponse.getErrorMessage())); + } + System.err.println(stockResponse.getErrorMessage()); + return; + } + if(successCallback != null) + successCallback.onSuccess(stockResponse); + System.out.println("Success Fetching Response!"); + }else{ + + if(failureCallback != null){ + failureCallback.onFailure(new AlphaVantageException()); + } + System.err.println("Error Fetching Response."); + } + } + }); + } + + + public abstract class RequestHelper implements Fetcher { + + protected TimeSeriesRequest.Builder builder; + + private RequestHelper(){ + + } + + public T forSymbol(String symbol){ + this.builder.forSymbol(symbol); + return (T)this; + } + + public T dataType(DataType type){ + this.builder.dataType(type); + return (T)this; + } + + @Override + public void fetch() { + TimeSeries.this.builder = this.builder; + TimeSeries.this.fetch(); + } + + + public T onSuccess(SuccessCallback callback) { + TimeSeries.this.successCallback = callback; + return (T)this; + } + + + public T onFailure(FailureCallback callback) { + TimeSeries.this.failureCallback = callback; + return (T)this; + } + } + + + public class DailyRequestHelper extends RequestHelper{ + + DailyRequestHelper() { + super(); + this.builder = DailyRequest.builder(); + } + + public DailyRequestHelper outputSize(OutputSize size){ + ((DailyRequest.Builder)this.builder).outputSize(size); + return this; + } + + public DailyRequestHelper adjusted(){ + TimeSeries.this.adjusted = true; + ((DailyRequest.Builder)this.builder).adjusted(); + return this; + } + + } + + public class IntraDayRequestHelper extends RequestHelper{ + + IntraDayRequestHelper() { + super(); + this.builder = IntraDayRequest.builder(); + } + + public IntraDayRequestHelper outputSize(OutputSize size){ + ((DailyRequest.Builder)this.builder).outputSize(size); + return this; + } + + public IntraDayRequestHelper interval(Interval interval){ + ((IntraDayRequest.Builder)this.builder).interval(interval); + return this; + } + } + + public class WeeklyRequestHelper extends RequestHelper{ + + WeeklyRequestHelper(){ + super(); + this.builder = WeeklyRequest.builder(); + } + + public WeeklyRequestHelper adjusted(){ + TimeSeries.this.adjusted = true; + ((WeeklyRequest.Builder)this.builder).adjusted(); + return this; + } + } + + public class MonthlyRequestHelper extends RequestHelper{ + + MonthlyRequestHelper(){ + super(); + this.builder = MonthlyRequest.builder(); + } + + public MonthlyRequestHelper adjusted(){ + TimeSeries.this.adjusted = true; + ((MonthlyRequest.Builder)this.builder).adjusted(); + return this; + } + } + +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/request/DailyRequest.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/DailyRequest.java new file mode 100644 index 0000000..2fdd638 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/DailyRequest.java @@ -0,0 +1,54 @@ +package com.crazzyghost.alphavantage.timeseries.request; + +import com.crazzyghost.alphavantage.parameters.Function; +import com.crazzyghost.alphavantage.parameters.OutputSize; + +public class DailyRequest extends TimeSeriesRequest{ + + private OutputSize outputSize; + private Function function; + + private DailyRequest(Builder builder){ + super(builder); + this.function = builder.function; + this.outputSize = builder.outputSize == null ? OutputSize.COMPACT : builder.outputSize ; + } + + +// @Override +// public void fetch(Fetcher fetcher) { +// fetcher.fetch(); +// } + + public static Builder builder(){ + return new Builder(); + } + + + public static class Builder extends TimeSeriesRequest.Builder{ + + Function function; + OutputSize outputSize; + + + public Builder(){ + super(); + function = Function.TIME_SERIES_DAILY; + } + + public Builder adjusted(){ + this.function = Function.TIME_SERIES_DAILY_ADJUSTED; + return this; + } + + public Builder outputSize(OutputSize outputSize){ + this.outputSize = outputSize; + return this; + } + + @Override + public DailyRequest build() { + return new DailyRequest(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/request/IntraDayRequest.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/IntraDayRequest.java new file mode 100644 index 0000000..4ea712b --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/IntraDayRequest.java @@ -0,0 +1,55 @@ +package com.crazzyghost.alphavantage.timeseries.request; + +import com.crazzyghost.alphavantage.parameters.Function; +import com.crazzyghost.alphavantage.parameters.Interval; +import com.crazzyghost.alphavantage.parameters.OutputSize; + +public class IntraDayRequest extends TimeSeriesRequest { + + private Interval interval; + private OutputSize outputSize; + private Function function; + + private IntraDayRequest(IntraDayRequest.Builder builder){ + super(builder); + this.function = Function.TIME_SERIES_INTRADAY; + this.interval = builder.interval == null ? Interval.ONE_MIN : builder.interval; + this.outputSize = builder.outputSize == null ? OutputSize.COMPACT : builder.outputSize ; + } + + + public static Builder builder(){ + return new Builder(); + } + + + public static class Builder extends TimeSeriesRequest.Builder{ + + Interval interval; + OutputSize outputSize; + + + public Builder(){ + super(); + } + + public Builder interval(Interval interval){ + this.interval = interval; + return this; + } + + + + public Builder outputSize(OutputSize outputSize){ + this.outputSize = outputSize; + return this; + } + + @Override + public IntraDayRequest build() { + return new IntraDayRequest(this); + } + } + + +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/request/MonthlyRequest.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/MonthlyRequest.java new file mode 100644 index 0000000..880e0c3 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/MonthlyRequest.java @@ -0,0 +1,37 @@ +package com.crazzyghost.alphavantage.timeseries.request; + +import com.crazzyghost.alphavantage.parameters.Function; + +public class MonthlyRequest extends TimeSeriesRequest { + + private Function function; + + public MonthlyRequest(Builder builder){ + super(builder); + this.function = builder.function; + } + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder extends TimeSeriesRequest.Builder{ + + private Function function; + + public Builder(){ + super(); + function = Function.TIME_SERIES_MONTHLY; + } + + public Builder adjusted(){ + function = Function.TIME_SERIES_MONTHLY_ADJUSTED; + return this; + } + + @Override + public MonthlyRequest build() { + return new MonthlyRequest(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/request/TimeSeriesRequest.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/TimeSeriesRequest.java new file mode 100644 index 0000000..9014577 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/TimeSeriesRequest.java @@ -0,0 +1,49 @@ +package com.crazzyghost.alphavantage.timeseries.request; + + +import com.crazzyghost.alphavantage.parameters.DataType; + +public abstract class TimeSeriesRequest { + + private DataType dataType; + private String symbol; + + + protected TimeSeriesRequest(Builder builder){ + this.symbol = builder.symbol; + this.dataType = builder.dataType == null ? DataType.JSON : builder.dataType; + } + + public static abstract class Builder>{ + + protected DataType dataType; + protected String symbol; + + public Builder(){ + + } + + + public T dataType(DataType dataType){ + this.dataType = dataType; + return (T) this; + } + + public T forSymbol(String symbol){ + this.symbol = symbol; + return (T) this; + } + + public abstract TimeSeriesRequest build(); + + } + + + @Override + public String toString() { + return "TimeSeriesRequest{" + + ", dataType=" + dataType + + ", symbol='" + symbol + '\'' + + '}'; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/request/WeeklyRequest.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/WeeklyRequest.java new file mode 100644 index 0000000..fffb572 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/request/WeeklyRequest.java @@ -0,0 +1,38 @@ +package com.crazzyghost.alphavantage.timeseries.request; + +import com.crazzyghost.alphavantage.parameters.Function; + +public class WeeklyRequest extends TimeSeriesRequest { + + + private Function function; + + public WeeklyRequest(Builder builder){ + super(builder); + this.function = builder.function; + } + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder extends TimeSeriesRequest.Builder{ + + private Function function; + + public Builder(){ + super(); + function = Function.TIME_SERIES_WEEKLY; + } + + public Builder adjusted(){ + function = Function.TIME_SERIES_WEEKLY_ADJUSTED; + return this; + } + + @Override + public WeeklyRequest build() { + return new WeeklyRequest(this); + } + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/response/MetaData.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/response/MetaData.java new file mode 100644 index 0000000..2d4e9c1 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/response/MetaData.java @@ -0,0 +1,45 @@ +package com.crazzyghost.alphavantage.timeseries.response; + +public class MetaData { + + private String information; + private String symbol; + private String lastRefreshed; + private String timeZone; + + public MetaData(String information, String symbol, String lastRefreshed, String timeZone) { + this.information = information; + this.symbol = symbol; + this.lastRefreshed = lastRefreshed; + this.timeZone = timeZone; + } + + public static MetaData empty(){ + return new MetaData("","","",""); + } + public String getInformation() { + return information; + } + + public String getSymbol() { + return symbol; + } + + public String getLastRefreshed() { + return lastRefreshed; + } + + public String getTimeZone() { + return timeZone; + } + + @Override + public String toString() { + return "MetaData{" + + "information='" + information + '\'' + + ", symbol='" + symbol + '\'' + + ", lastRefreshed='" + lastRefreshed + '\'' + + ", timeZone='" + timeZone + '\'' + + '}'; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/response/StockUnit.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/response/StockUnit.java new file mode 100644 index 0000000..2833461 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/response/StockUnit.java @@ -0,0 +1,129 @@ +package com.crazzyghost.alphavantage.timeseries.response; + +public class StockUnit { + + private double open; + private double high; + private double low; + private double close; + private double adjustedClose; + private long volume; + private double dividendAmount; + private double splitCoefficient; + + private StockUnit(Builder builder) { + this.open = builder.open; + this.high = builder.high; + this.low = builder.low; + this.close = builder.close; + this.adjustedClose = builder.adjustedClose; + this.volume = builder.volume; + this.dividendAmount = builder.dividendAmount; + this.splitCoefficient = builder.splitCoefficient; + } + + public static Builder builder(){ + return new Builder(); + } + + public static class Builder{ + + double open; + double high; + double low; + double close; + double adjustedClose; + long volume; + double dividendAmount; + double splitCoefficient; + + public Builder open(double open){ + this.open = open; + return this; + } + + public Builder high(double high){ + this.high = open; + return this; + } + public Builder low(double low){ + this.low = low; + return this; + } + + public Builder close(double close){ + this.close = low; + return this; + } + public Builder adjustedClose(double close){ + this.adjustedClose = close; + return this; + } + + public Builder dividendAmount(double dividendAmount){ + this.dividendAmount = dividendAmount; + return this; + } + + public Builder volume(long volume){ + this.volume = volume; + return this; + } + + public Builder splitCoefficient(double splitCoefficient){ + this.splitCoefficient = splitCoefficient; + return this; + } + + + public StockUnit build(){ + return new StockUnit(this); + } + } + + public double getOpen() { + return open; + } + + public double getHigh() { + return high; + } + + public double getLow() { + return low; + } + + public double getClose() { + return close; + } + + public double getAdjustedClose() { + return adjustedClose; + } + + public long getVolume() { + return volume; + } + + public double getDividendAmount() { + return dividendAmount; + } + + public double getSplitCoefficient() { + return splitCoefficient; + } + + @Override + public String toString() { + return "StockUnit{" + + "open=" + open + + ", high=" + high + + ", low=" + low + + ", close=" + close + + ", adjustedClose=" + adjustedClose + + ", volume=" + volume + + ", dividendAmount=" + dividendAmount + + ", splitCoefficient=" + splitCoefficient + + '}'; + } +} diff --git a/src/main/java/com/crazzyghost/alphavantage/timeseries/response/TimeSeriesResponse.java b/src/main/java/com/crazzyghost/alphavantage/timeseries/response/TimeSeriesResponse.java new file mode 100644 index 0000000..8583181 --- /dev/null +++ b/src/main/java/com/crazzyghost/alphavantage/timeseries/response/TimeSeriesResponse.java @@ -0,0 +1,108 @@ +package com.crazzyghost.alphavantage.timeseries.response; + +import com.crazzyghost.alphavantage.AlphaVantageException; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class TimeSeriesResponse { + + private MetaData metaData; + private List stockUnits; + private String errorMessage; + + private TimeSeriesResponse(MetaData metaData, List stockUnits) { + this.metaData = metaData; + this.stockUnits = stockUnits; + this.errorMessage = null; + } + + private TimeSeriesResponse(String errorMessage){ + this.errorMessage = errorMessage; + this.stockUnits = new ArrayList<>(); + this.metaData = MetaData.empty(); + } + + public static TimeSeriesResponse of(Map raw, boolean adjusted){ + Parser parser = new Parser(adjusted); + return parser.parse(raw); + } + + public String getErrorMessage() { + return errorMessage; + } + + public MetaData getMetaData() { + return metaData; + } + + public List getStockUnits() { + return stockUnits; + } + + public static class Parser { + + private boolean adjusted; + + Parser(boolean adjusted){ + this.adjusted = adjusted; + } + + TimeSeriesResponse parse(Map stringObjectMap) { + + //get the keys + List keys = new ArrayList<>(stringObjectMap.keySet()); + + Map md; + Map> stockData; + + try{ + md = (Map) stringObjectMap.get(keys.get(0)); + stockData = (Map>) stringObjectMap.get(keys.get(1)); + + }catch (ClassCastException ex){ + return new TimeSeriesResponse((String)stringObjectMap.get(keys.get(0))); + } + + MetaData metaData = new MetaData( + md.get("1. Information"), + md.get("2. Symbol"), + md.get("3. Last Refreshed"), + md.get("4. Time Zone") + ); + + List stockUnits = new ArrayList<>(); + + for (Map m: stockData.values()) { + StockUnit.Builder stockUnit = StockUnit.builder(); + stockUnit.open(Double.parseDouble(m.get("1. open"))); + stockUnit.high(Double.parseDouble(m.get("2. high"))); + stockUnit.low(Double.parseDouble(m.get("3. low"))); + stockUnit.close(Double.parseDouble(m.get("4. close"))); + if(!adjusted){ + stockUnit.volume(Long.parseLong(m.get("5. volume"))); + }else{ + stockUnit.adjustedClose(Double.parseDouble(m.get("5. adjusted close"))); + stockUnit.volume(Long.parseLong(m.get("6. volume"))); + stockUnit.dividendAmount(Double.parseDouble(m.get("7. dividend amount"))); + if(m.get("8. split coefficient") != null) + stockUnit.splitCoefficient(Double.parseDouble(m.get("8. split coefficient"))); + } + stockUnits.add(stockUnit.build()); + } + return new TimeSeriesResponse(metaData, stockUnits); + } + } + + + @Override + public String toString() { + return "ForexResponse{" + + "metaData=" + metaData + + ", forexUnits=" + stockUnits.size() + + ", errorMessage='" + errorMessage + '\'' + + '}'; + } +} +