Added keywords symbol lookup.
This commit is contained in:
parent
8931405ee9
commit
2775cca3aa
2 changed files with 92 additions and 59 deletions
|
@ -42,12 +42,14 @@ import net.thauvin.erik.mobibot.msg.PublicMessage;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The StockQuote module.
|
* The StockQuote module.
|
||||||
|
@ -61,9 +63,12 @@ public final class StockQuote extends ThreadedModule {
|
||||||
* The Alpha Advantage property key.
|
* The Alpha Advantage property key.
|
||||||
*/
|
*/
|
||||||
static final String ALPHAVANTAGE_API_KEY_PROP = "alphavantage-api-key";
|
static final String ALPHAVANTAGE_API_KEY_PROP = "alphavantage-api-key";
|
||||||
|
/**
|
||||||
|
* The Invalid Symbol error string.
|
||||||
|
*/
|
||||||
|
static final String INVALID_SYMBOL = "Invalid symbol.";
|
||||||
// The Alpha Advantage URL.
|
// The Alpha Advantage URL.
|
||||||
private static final String ALAPHADVANTAGE_URL = "https://www.alphavantage.co/query?function=GLOBAL_QUOTE";
|
private static final String ALAPHADVANTAGE_URL = "https://www.alphavantage.co/query?function=";
|
||||||
// The quote command.
|
// The quote command.
|
||||||
private static final String STOCK_CMD = "stock";
|
private static final String STOCK_CMD = "stock";
|
||||||
|
|
||||||
|
@ -93,74 +98,71 @@ public final class StockQuote extends ThreadedModule {
|
||||||
final String debugMessage = "getQuote(" + symbol + ')';
|
final String debugMessage = "getQuote(" + symbol + ')';
|
||||||
final ArrayList<Message> messages = new ArrayList<>();
|
final ArrayList<Message> messages = new ArrayList<>();
|
||||||
final OkHttpClient client = new OkHttpClient();
|
final OkHttpClient client = new OkHttpClient();
|
||||||
final Request request =
|
|
||||||
new Request.Builder().url(ALAPHADVANTAGE_URL + "&symbol=" + symbol + "&apikey=" + apiKey).build();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final Response response = client.newCall(request).execute();
|
// Search for symbol/keywords
|
||||||
|
Request request = new Request.Builder().url(
|
||||||
|
ALAPHADVANTAGE_URL + "SYMBOL_SEARCH&keywords=" + symbol + "&apikey=" + apiKey).build();
|
||||||
|
Response response = client.newCall(request).execute();
|
||||||
|
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
final JSONObject json = new JSONObject(response.body().string());
|
JSONObject json = new JSONObject(Objects.requireNonNull(response.body()).string());
|
||||||
|
if (isValidJsonObject(json, debugMessage)) {
|
||||||
try {
|
final JSONArray symbols = json.getJSONArray("bestMatches");
|
||||||
final String info = json.getString("Information");
|
if (symbols.isEmpty()) {
|
||||||
if (!info.isEmpty()) {
|
messages.add(new ErrorMessage(INVALID_SYMBOL));
|
||||||
throw new ModuleException(debugMessage, Utils.unescapeXml(info));
|
return messages;
|
||||||
}
|
}
|
||||||
} catch (JSONException ignore) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
final JSONObject symbolInfo = symbols.getJSONObject(0);
|
||||||
final String error = json.getString("Error Message");
|
|
||||||
if (!error.isEmpty()) {
|
// Get quote for symbol
|
||||||
if (error.startsWith("Invalid API call.")) {
|
request = new Request.Builder().url(
|
||||||
throw new ModuleException(debugMessage + ": " + Utils.unescapeXml(error),
|
ALAPHADVANTAGE_URL + "GLOBAL_QUOTE&symbol=" + symbolInfo.getString("1. symbol") + "&apikey="
|
||||||
"Invalid symbol.");
|
+ apiKey).build();
|
||||||
} else {
|
response = client.newCall(request).execute();
|
||||||
throw new ModuleException(debugMessage, Utils.unescapeXml(error));
|
if (response.body() != null) {
|
||||||
|
json = new JSONObject(Objects.requireNonNull(response.body()).string());
|
||||||
|
|
||||||
|
if (isValidJsonObject(json, debugMessage)) {
|
||||||
|
final JSONObject quote = json.getJSONObject("Global Quote");
|
||||||
|
|
||||||
|
if (quote.isEmpty()) {
|
||||||
|
messages.add(new ErrorMessage(INVALID_SYMBOL));
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.add(new PublicMessage(
|
||||||
|
"Symbol: " + Utils.unescapeXml(quote.getString("01. symbol")) + " [" + Utils
|
||||||
|
.unescapeXml(symbolInfo.getString("2. name") + ']')));
|
||||||
|
messages.add(new PublicMessage(
|
||||||
|
" Price: " + Utils.unescapeXml(quote.getString("05. price"))));
|
||||||
|
messages.add(new PublicMessage(
|
||||||
|
" Previous: " + Utils.unescapeXml(quote.getString("08. previous close"))));
|
||||||
|
messages.add(new NoticeMessage(
|
||||||
|
" Open: " + Utils.unescapeXml(quote.getString("02. open"))));
|
||||||
|
messages.add(new NoticeMessage(
|
||||||
|
" High: " + Utils.unescapeXml(quote.getString("03. high"))));
|
||||||
|
messages.add(new NoticeMessage(
|
||||||
|
" Low: " + Utils.unescapeXml(quote.getString("04. low"))));
|
||||||
|
messages.add(new NoticeMessage(
|
||||||
|
" Volume: " + Utils.unescapeXml(quote.getString("06. volume"))));
|
||||||
|
messages.add(new NoticeMessage(
|
||||||
|
" Latest: " + Utils.unescapeXml(quote.getString("07. latest trading day"))));
|
||||||
|
messages.add(new NoticeMessage(
|
||||||
|
" Change: " + Utils.unescapeXml(quote.getString("09. change")) + " [" + Utils
|
||||||
|
.unescapeXml(quote.getString("10. change percent")) + ']'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (JSONException ignore) {
|
|
||||||
// Do nothing.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final JSONObject quote = json.getJSONObject("Global Quote");
|
|
||||||
|
|
||||||
if (quote.isEmpty()) {
|
|
||||||
messages.add(new ErrorMessage("Invalid symbol."));
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
messages.add(
|
|
||||||
new PublicMessage("Symbol: " + Utils.unescapeXml(quote.getString("01. symbol"))));
|
|
||||||
messages.add(
|
|
||||||
new PublicMessage(" Price: " + Utils.unescapeXml(quote.getString("05. price"))));
|
|
||||||
messages.add(
|
|
||||||
new PublicMessage(" Previous: "
|
|
||||||
+ Utils.unescapeXml(quote.getString("08. previous close"))));
|
|
||||||
messages.add(
|
|
||||||
new NoticeMessage(" Open: " + Utils.unescapeXml(quote.getString("02. open"))));
|
|
||||||
messages.add(
|
|
||||||
new NoticeMessage(" High: " + Utils.unescapeXml(quote.getString("03. high"))));
|
|
||||||
messages.add(
|
|
||||||
new NoticeMessage(" Low: " + Utils.unescapeXml(quote.getString("04. low"))));
|
|
||||||
messages.add(
|
|
||||||
new NoticeMessage(" Volume: " + Utils.unescapeXml(quote.getString("06. volume"))));
|
|
||||||
messages.add(
|
|
||||||
new NoticeMessage(" Latest: "
|
|
||||||
+ Utils.unescapeXml(quote.getString("07. latest trading day"))));
|
|
||||||
messages.add(
|
|
||||||
new NoticeMessage(" Change: " + Utils.unescapeXml(quote.getString("09. change"))
|
|
||||||
+ " [" + Utils.unescapeXml(quote.getString("10. change percent")) + ']'));
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ModuleException(debugMessage, "An error has occurred retrieving a stock quote.", e);
|
throw new ModuleException(debugMessage, "An error has occurred retrieving a stock quote.", e);
|
||||||
}
|
}
|
||||||
return messages;
|
return messages;
|
||||||
} else {
|
} else {
|
||||||
throw new ModuleException("Invalid symbol.");
|
throw new ModuleException(INVALID_SYMBOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,7 +171,38 @@ public final class StockQuote extends ThreadedModule {
|
||||||
@Override
|
@Override
|
||||||
public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) {
|
public void helpResponse(final Mobibot bot, final String sender, final String args, final boolean isPrivate) {
|
||||||
bot.send(sender, "To retrieve a stock quote:");
|
bot.send(sender, "To retrieve a stock quote:");
|
||||||
bot.send(sender, bot.helpIndent(bot.getNick() + ": " + STOCK_CMD + " <symbol>"));
|
bot.send(sender, bot.helpIndent(bot.getNick() + ": " + STOCK_CMD + " <symbol|keywords>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isValidJsonObject(final JSONObject json, final String debugMessage) throws ModuleException {
|
||||||
|
try {
|
||||||
|
final String info = json.getString("Information");
|
||||||
|
if (!info.isEmpty()) {
|
||||||
|
throw new ModuleException(debugMessage, Utils.unescapeXml(info));
|
||||||
|
}
|
||||||
|
} catch (JSONException ignore) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String error = json.getString("Note");
|
||||||
|
if (!error.isEmpty()) {
|
||||||
|
throw new ModuleException(debugMessage, Utils.unescapeXml(error));
|
||||||
|
}
|
||||||
|
} catch (JSONException ignore) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String error = json.getString("Error Message");
|
||||||
|
if (!error.isEmpty()) {
|
||||||
|
throw new ModuleException(debugMessage, Utils.unescapeXml(error));
|
||||||
|
}
|
||||||
|
} catch (JSONException ignore) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -56,14 +56,14 @@ public class StockQuoteTest extends LocalProperties {
|
||||||
public void testGetQuote() throws ModuleException {
|
public void testGetQuote() throws ModuleException {
|
||||||
final String apiKey = LocalProperties.getProperty(StockQuote.ALPHAVANTAGE_API_KEY_PROP);
|
final String apiKey = LocalProperties.getProperty(StockQuote.ALPHAVANTAGE_API_KEY_PROP);
|
||||||
try {
|
try {
|
||||||
final List<Message> messages = StockQuote.getQuote("AAPL", apiKey);
|
final List<Message> messages = StockQuote.getQuote("apple inc", apiKey);
|
||||||
assertThat(messages).as("response not empty").isNotEmpty();
|
assertThat(messages).as("response not empty").isNotEmpty();
|
||||||
assertThat(messages.get(0).getMessage()).as("same stock symbol").contains("AAPL");
|
assertThat(messages.get(0).getMessage()).as("same stock symbol").contains("AAPL").contains("Apple Inc.");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
StockQuote.getQuote("012", apiKey);
|
StockQuote.getQuote("012", apiKey);
|
||||||
} catch (ModuleException e) {
|
} catch (ModuleException e) {
|
||||||
assertThat(e.getMessage()).as("invalid symbol").containsIgnoringCase("invalid symbol");
|
assertThat(e.getMessage()).as("invalid symbol").containsIgnoringCase(StockQuote.INVALID_SYMBOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThatThrownBy(() -> StockQuote.getQuote("test", "")).as("no API key").isInstanceOf(
|
assertThatThrownBy(() -> StockQuote.getQuote("test", "")).as("no API key").isInstanceOf(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue