import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.SocketTimeoutException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.datatype.joda.JodaModule; import com.espertech.esper.client.time.CurrentTimeEvent; import javax.net.ssl.HttpsURLConnection; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; public class OANDAReader implements TickStreamReader { final Logger log = LoggerFactory.getLogger(OANDAReader.class); ObjectMapper mapper; AccountInfo accountInfo; String[] instruments; public OANDAReader(AccountInfo accountInfo, String[] instruments) { this.accountInfo = accountInfo; this.instruments = instruments; mapper = new ObjectMapper(); mapper.registerModule(new JodaModule()); } public void run(TickProcessor processor) { readConnection(streamURL(), processor); } private String streamURL() { String type = accountInfo.isLiveAccount() ? "fxlive" : "fxpractice"; String instrList = String.join(",", instruments); String query = ""; try { query = String.format("instruments=%s", URLEncoder.encode(instrList, "UTF-8")); } catch (UnsupportedEncodingException e) { log.error("Creating stream URL", e); } return String.format("https://stream-%s.oanda.com/v3/accounts/%s/pricing/stream?%s", type, accountInfo.accountID(), query); } private void readConnection(String urlStr, TickProcessor processor) { HttpsURLConnection httpConn = null; String line = null; try { URL url = new URL(urlStr); URLConnection urlConn = url.openConnection(); if (!(urlConn instanceof HttpsURLConnection)) { throw new IOException ("URL is not an https URL"); } httpConn = (HttpsURLConnection)urlConn; httpConn.setAllowUserInteraction(false); //httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET"); //httpConn.setReadTimeout(50 * 1000); httpConn.setRequestProperty("Authorization", "Bearer 9a480f0b83e987f4015cf0846790c7d9-695ced635526744abd61bdf0e2ae8b71"); BufferedReader is = new BufferedReader(new InputStreamReader(httpConn.getInputStream())); while ((line = is.readLine( )) != null) { processLine(line, processor); } } catch (IOException e) { log.error("Reading OANDA stream", e); } finally { httpConn.disconnect(); } } private void processLine(String line, TickProcessor processor) { if (line.indexOf ("PRICE") > -1) { OANDATickEvent tick; try { tick = mapper.readValue(line, OANDATickEvent.class); processor.process(tick); } catch (JsonParseException | JsonMappingException e) { log.error("Parsing OANDA tick", e); } catch (IOException e) { log.error("Parsing OANDA tick", e); } } else if (line.indexOf ("HEARTBEAT") > -1) { try { OANDAHeartbeatEvent beat = mapper.readValue(line, OANDAHeartbeatEvent.class); processor.process(new CurrentTimeEvent(beat.getTime().getMillis())); } catch (IOException e) { log.error("Parsing OANDA heartbeat", e); } } else { log.warn("Unknown type: {}", line); } } }