/* * Copyright (c) 2004-2011 Marco Maccaferri and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marco Maccaferri - initial API and implementation */ package org.eclipsetrader.directa.internal.core; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.core.net.proxy.IProxyData; import org.eclipse.core.net.proxy.IProxyService; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.security.storage.ISecurePreferences; import org.eclipse.equinox.security.storage.SecurePreferencesFactory; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.window.Window; import org.eclipse.swt.widgets.Display; import org.eclipsetrader.core.feed.FeedIdentifier; import org.eclipsetrader.core.feed.IFeedIdentifier; import org.eclipsetrader.core.feed.IFeedProperties; import org.eclipsetrader.core.instruments.ISecurity; import org.eclipsetrader.core.instruments.Security; import org.eclipsetrader.core.repositories.IRepositoryService; import org.eclipsetrader.core.trading.IOrder; import org.eclipsetrader.core.trading.IOrderSide; import org.eclipsetrader.core.trading.IOrderStatus; import org.eclipsetrader.core.trading.IOrderType; import org.eclipsetrader.core.trading.IOrderValidity; import org.eclipsetrader.directa.internal.Activator; import org.eclipsetrader.directa.internal.core.connector.LoginDialog; import org.htmlparser.Parser; import org.htmlparser.filters.HasAttributeFilter; import org.htmlparser.filters.NodeClassFilter; import org.htmlparser.nodes.RemarkNode; import org.htmlparser.tags.LinkTag; import org.htmlparser.tags.OptionTag; import org.htmlparser.tags.SelectTag; import org.htmlparser.tags.TableColumn; import org.htmlparser.tags.TableHeader; import org.htmlparser.tags.TableRow; import org.htmlparser.util.NodeList; import org.htmlparser.util.SimpleNodeIterator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; public class WebConnector { private static WebConnector instance; private static final String HOST = "www1.directatrading.com"; //$NON-NLS-1$ public static final String[] PROPERTIES = new String[] { "org.eclipsetrader.directa.symbol", //$NON-NLS-1$ "org.eclipsetrader.directaworld.symbol", //$NON-NLS-1$ "org.eclipsetrader.borsaitalia.code", //$NON-NLS-1$ }; private HttpClient client; private String userName; private String password; private Account account; private String prt = ""; //$NON-NLS-1$ private String urt = ""; //$NON-NLS-1$ private String user = ""; //$NON-NLS-1$ private NumberFormat numberFormatter = NumberFormat.getInstance(Locale.ITALY); private Log logger = LogFactory.getLog(getClass()); WebConnector() { instance = this; File file = null; if (Activator.getDefault() != null) { file = Activator.getDefault().getStateLocation().append("positions.xml").toFile(); //$NON-NLS-1$ } account = new Account(Messages.WebConnector_DefaultAccount, file); account.load(); } public synchronized static WebConnector getInstance() { if (instance == null) { instance = new WebConnector(); } return instance; } public boolean isLoggedIn() { return user != null && !"".equals(user); //$NON-NLS-1$ } public synchronized void login() { final IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); final ISecurePreferences securePreferences; if (preferenceStore.getBoolean(Activator.PREFS_USE_SECURE_PREFERENCE_STORE)) { securePreferences = SecurePreferencesFactory.getDefault().node(Activator.PLUGIN_ID); try { if (userName == null) { userName = securePreferences.get(Activator.PREFS_USERNAME, ""); //$NON-NLS-1$ } if (password == null) { password = securePreferences.get(Activator.PREFS_PASSWORD, ""); //$NON-NLS-1$ } } catch (Exception e) { final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error accessing secure storage", e); //$NON-NLS-1$ Display.getDefault().syncExec(new Runnable() { @Override public void run() { Activator.log(status); ErrorDialog.openError(null, null, null, status); } }); } } else { securePreferences = null; if (userName == null) { userName = preferenceStore.getString(Activator.PREFS_USERNAME); } if (password == null) { password = preferenceStore.getString(Activator.PREFS_PASSWORD); } } prt = ""; //$NON-NLS-1$ urt = ""; //$NON-NLS-1$ user = ""; //$NON-NLS-1$ do { if (userName == null || password == null || "".equals(userName) || "".equals(password)) { //$NON-NLS-1$ //$NON-NLS-2$ Display.getDefault().syncExec(new Runnable() { @Override public void run() { LoginDialog dlg = new LoginDialog(null, userName, password); if (dlg.open() == Window.OK) { userName = dlg.getUserName(); password = dlg.getPassword(); if (dlg.isSavePassword()) { if (preferenceStore.getBoolean(Activator.PREFS_USE_SECURE_PREFERENCE_STORE)) { try { securePreferences.put(Activator.PREFS_USERNAME, userName, true); securePreferences.put(Activator.PREFS_PASSWORD, dlg.isSavePassword() ? password : "", true); //$NON-NLS-1$ } catch (Exception e) { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error accessing secure storage", e); //$NON-NLS-1$ Activator.log(status); ErrorDialog.openError(null, null, null, status); } } else { preferenceStore.putValue(Activator.PREFS_USERNAME, userName); preferenceStore.putValue(Activator.PREFS_PASSWORD, dlg.isSavePassword() ? password : ""); //$NON-NLS-1$ } } } else { userName = null; password = null; } } }); if (userName == null || password == null) { return; } } if (client == null) { client = new HttpClient(); client.getHttpConnectionManager().getParams().setConnectionTimeout(30000); try { setupProxy(client, HOST); } catch (URISyntaxException e) { final Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error setting proxy", e); //$NON-NLS-1$ Display.getDefault().syncExec(new Runnable() { @Override public void run() { Activator.log(status); ErrorDialog.openError(null, null, null, status); } }); } } try { HttpMethod method = new GetMethod("https://" + HOST + "/trading/collegc_3"); //$NON-NLS-1$ //$NON-NLS-2$ method.setFollowRedirects(true); method.setQueryString(new NameValuePair[] { new NameValuePair("USER", userName), //$NON-NLS-1$ new NameValuePair("PASSW", password), //$NON-NLS-1$ new NameValuePair("PAG", "VT4.4.0.6"), //$NON-NLS-1$ //$NON-NLS-2$ new NameValuePair("TAPPO", "X"), //$NON-NLS-1$ //$NON-NLS-2$ }); logger.debug(method.getURI().toString()); client.executeMethod(method); Parser parser = Parser.createParser(method.getResponseBodyAsString(), ""); //$NON-NLS-1$ NodeList list = parser.extractAllNodesThatMatch(new NodeClassFilter(RemarkNode.class)); for (SimpleNodeIterator iter = list.elements(); iter.hasMoreNodes();) { RemarkNode node = (RemarkNode) iter.nextNode(); String text = node.getText(); if (text.startsWith("USER")) { //$NON-NLS-1$ user = text.substring(4); } if (text.startsWith("URT")) { //$NON-NLS-1$ urt = text.substring(3); } else if (text.startsWith("PRT")) { //$NON-NLS-1$ prt = text.substring(3); } } } catch (Exception e) { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error connecting to login server", e); //$NON-NLS-1$ Activator.log(status); return; } if (user.equals("") || prt.equals("") || urt.equals("")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ password = ""; //$NON-NLS-1$ } } while (user.equals("") || prt.equals("") || urt.equals("")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ account.setId(userName); } public Account getAccount() { if (userName == null) { IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); userName = preferenceStore.getString(Activator.PREFS_USERNAME); if (!"".equals(userName)) { //$NON-NLS-1$ account.setId(userName); } } return account; } private void setupProxy(HttpClient client, String host) throws URISyntaxException { if (Activator.getDefault() != null) { BundleContext context = Activator.getDefault().getBundle().getBundleContext(); ServiceReference reference = context.getServiceReference(IProxyService.class.getName()); if (reference != null) { IProxyService proxyService = (IProxyService) context.getService(reference); IProxyData[] proxyData = proxyService.select(new URI(null, host, null, null)); for (int i = 0; i < proxyData.length; i++) { if (IProxyData.HTTP_PROXY_TYPE.equals(proxyData[i].getType())) { IProxyData data = proxyData[i]; if (data.getHost() != null) { client.getHostConfiguration().setProxy(data.getHost(), data.getPort()); } if (data.isRequiresAuthentication()) { client.getState().setProxyCredentials(AuthScope.ANY, new UsernamePasswordCredentials(data.getUserId(), data.getPassword())); } break; } } context.ungetService(reference); } } } protected IPreferenceStore getPreferenceStore() { return Activator.getDefault().getPreferenceStore(); } public String getPrt() { return prt; } public String getUrt() { return urt; } public String getUser() { return user; } protected ISecurity getSecurityFromSymbol(String symbol) { ISecurity security = null; if (Activator.getDefault() != null) { BundleContext context = Activator.getDefault().getBundle().getBundleContext(); ServiceReference serviceReference = context.getServiceReference(IRepositoryService.class.getName()); if (serviceReference != null) { IRepositoryService service = (IRepositoryService) context.getService(serviceReference); ISecurity[] securities = service.getSecurities(); for (int i = 0; i < securities.length; i++) { String feedSymbol = getSecurityFeedSymbol(securities[i]); if (feedSymbol != null && feedSymbol.equals(symbol)) { security = securities[i]; break; } } context.ungetService(serviceReference); } } if (security == null) { security = new Security(symbol, new FeedIdentifier(symbol, null)); } return security; } protected String getSecurityFeedSymbol(ISecurity security) { IFeedIdentifier identifier = security.getIdentifier(); if (identifier == null) { return null; } String symbol = identifier.getSymbol(); IFeedProperties properties = (IFeedProperties) identifier.getAdapter(IFeedProperties.class); if (properties != null) { for (int p = 0; p < PROPERTIES.length; p++) { if (properties.getProperty(PROPERTIES[p]) != null) { symbol = properties.getProperty(PROPERTIES[p]); break; } } } return symbol; } public boolean sendOrder(OrderMonitor tracker) { boolean ok = false; boolean confirm = false; String inputLine; IOrder order = tracker.getOrder(); List<NameValuePair> query = new ArrayList<NameValuePair>(); query.add(new NameValuePair("ACQAZ", order.getSide() == IOrderSide.Buy ? String.valueOf(order.getQuantity()) : "")); //$NON-NLS-1$ //$NON-NLS-2$ query.add(new NameValuePair("VENAZ", order.getSide() == IOrderSide.Sell ? String.valueOf(order.getQuantity()) : "")); //$NON-NLS-1$ //$NON-NLS-2$ query.add(new NameValuePair("PRZACQ", order.getType() != IOrderType.Market ? numberFormatter.format(order.getPrice()) : "")); //$NON-NLS-1$ //$NON-NLS-2$ query.add(new NameValuePair("SCTLX", "immetti Borsa Ita")); //$NON-NLS-1$ //$NON-NLS-2$ query.add(new NameValuePair("USER", user)); //$NON-NLS-1$ query.add(new NameValuePair("GEST", "AZIONARIO")); //$NON-NLS-1$ //$NON-NLS-2$ query.add(new NameValuePair("TITO", getSecurityFeedSymbol(order.getSecurity()))); //$NON-NLS-1$ query.add(new NameValuePair("QPAR", "")); //$NON-NLS-1$ //$NON-NLS-2$ if (order.getValidity() == IOrderValidity.GoodTillCancel || order.getValidity() == BrokerConnector.Valid30Days) { query.add(new NameValuePair("VALID", "M")); //$NON-NLS-1$ //$NON-NLS-2$ } query.add(new NameValuePair("FAS5", order.getRoute() != null ? order.getRoute().getId() : BrokerConnector.Immediate.getId())); //$NON-NLS-1$ // Inserisce l'ordine di acquisto try { GetMethod method = new GetMethod("https://" + HOST + "/trading/ordimm5c"); //$NON-NLS-1$ //$NON-NLS-2$ method.setFollowRedirects(true); query.add(new NameValuePair("MODO", "C")); //$NON-NLS-1$ //$NON-NLS-2$ method.setQueryString(query.toArray(new NameValuePair[query.size()])); logger.debug(method.getURI().toString()); client.executeMethod(method); BufferedReader in = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream())); while ((inputLine = in.readLine()) != null) { logger.debug(inputLine); if (inputLine.indexOf("VI TRASMETTO L'ORDINE DI") != -1) { //$NON-NLS-1$ ok = true; confirm = true; } if (inputLine.indexOf("ORDINE IMMESSO") != -1) { //$NON-NLS-1$ ok = true; confirm = false; } if (!confirm && tracker.getId() == null) { int s = inputLine.indexOf("<i>rif. "); //$NON-NLS-1$ if (s != -1) { s = inputLine.indexOf(">", s + 13) + 1; //$NON-NLS-1$ int e = inputLine.indexOf("<", s); //$NON-NLS-1$ tracker.setId(inputLine.substring(s, e)); } } } in.close(); } catch (Exception e) { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error sending order [" + order.toString() + "]", e); //$NON-NLS-1$ //$NON-NLS-2$ Activator.log(status); } // Se viene richiesta invia anche la conferma d'ordine if (ok && confirm) { ok = false; try { GetMethod method = new GetMethod("https://" + HOST + "/trading/ordimm5c"); //$NON-NLS-1$ //$NON-NLS-2$ method.setFollowRedirects(true); query.remove(new NameValuePair("MODO", "C")); //$NON-NLS-1$ //$NON-NLS-2$ query.add(new NameValuePair("MODO", "V")); //$NON-NLS-1$ //$NON-NLS-2$ method.setQueryString(query.toArray(new NameValuePair[query.size()])); logger.debug(method.getURI().toString()); client.executeMethod(method); BufferedReader in = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream())); while ((inputLine = in.readLine()) != null) { logger.debug(inputLine); if (inputLine.indexOf("ORDINE IMMESSO") != -1) { //$NON-NLS-1$ ok = true; } if (ok && tracker.getId() == null) { int s = inputLine.indexOf("<i>rif. "); //$NON-NLS-1$ if (s != -1) { s = inputLine.indexOf(">", s) + 1; //$NON-NLS-1$ int e = inputLine.indexOf("<", s); //$NON-NLS-1$ tracker.setId(inputLine.substring(s, e)); } } } in.close(); } catch (Exception e) { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error confirming order [" + order.toString() + "]", e); //$NON-NLS-1$ //$NON-NLS-2$ Activator.log(status); } } if (ok) { if (logger.isInfoEnabled()) { StringBuilder sb = new StringBuilder("Order Submitted:"); sb.append(" id=" + tracker.getId()); sb.append(", instrument=" + tracker.getOrder().getSecurity().getName()); sb.append(", type=" + tracker.getOrder().getType()); sb.append(", side=" + tracker.getOrder().getSide()); sb.append(", qty=" + tracker.getOrder().getQuantity()); if (tracker.getOrder().getPrice() != null) { sb.append(", price=" + tracker.getOrder().getPrice()); } if (tracker.getOrder().getReference() != null) { sb.append(", reference=" + tracker.getOrder().getReference()); } logger.info(sb.toString()); } tracker.setStatus(IOrderStatus.PendingNew); } return ok; } public boolean cancelOrder(OrderMonitor tracker) { boolean ok = false; String inputLine; try { GetMethod method = new GetMethod("https://" + HOST + "/trading/ordmod5c"); //$NON-NLS-1$ //$NON-NLS-2$ method.setQueryString(new NameValuePair[] { new NameValuePair("TAST", "REVOCA"), //$NON-NLS-1$ //$NON-NLS-2$ new NameValuePair("USER", user), //$NON-NLS-1$ new NameValuePair("RIF", tracker.getId()), //$NON-NLS-1$ new NameValuePair("TIPO", "I"), //$NON-NLS-1$ //$NON-NLS-2$ new NameValuePair("PRZO", ""), //$NON-NLS-1$ //$NON-NLS-2$ new NameValuePair("TITO", getSecurityFeedSymbol(tracker.getOrder().getSecurity())), //$NON-NLS-1$ new NameValuePair("FILL", "REVOCA"), //$NON-NLS-1$ //$NON-NLS-2$ }); logger.debug(method.getURI().toString()); client.executeMethod(method); BufferedReader in = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream())); while ((inputLine = in.readLine()) != null) { logger.debug(inputLine); if (inputLine.indexOf("INOLTRATA LA RICHIESTA DI REVOCA") != -1 || inputLine.indexOf("RICH.ANN.") != -1) { //$NON-NLS-1$ //$NON-NLS-2$ ok = true; } } in.close(); } catch (Exception e) { Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error canceling order [" + tracker.toString() + "]", e); //$NON-NLS-1$ //$NON-NLS-2$ Activator.log(status); } if (ok) { tracker.setStatus(IOrderStatus.PendingCancel); } return ok; } public void importWatchlists() { try { GetMethod method = new GetMethod("https://" + HOST + "/trading/select"); //$NON-NLS-1$ //$NON-NLS-2$ method.setFollowRedirects(true); method.setQueryString(new NameValuePair[] { new NameValuePair("USER", user), //$NON-NLS-1$ new NameValuePair("INCR", "N"), //$NON-NLS-1$ //$NON-NLS-2$ }); logger.debug(method.getURI().toString()); client.executeMethod(method); Parser parser = Parser.createParser(method.getResponseBodyAsString(), ""); //$NON-NLS-1$ NodeList list = parser.extractAllNodesThatMatch(new HasAttributeFilter("name", "DEVAR")); //$NON-NLS-1$ //$NON-NLS-2$ for (SimpleNodeIterator iter = list.elements(); iter.hasMoreNodes();) { Object o = iter.nextNode(); if (o instanceof SelectTag) { OptionTag[] options = ((SelectTag) o).getOptionTags(); for (int i = 0; i < options.length; i++) { if (options[i].getValue().equals("A0") || options[i].getValue().equals("AX")) { //$NON-NLS-1$ //$NON-NLS-2$ continue; } System.out.println(options[i].getValue() + " -> " + options[i].getOptionText()); //$NON-NLS-1$ getWatchlist(options[i].getValue(), options[i].getOptionText()); } } } } catch (Exception e) { e.printStackTrace(); } } protected void getWatchlist(String id, String title) { try { HttpMethod method = new GetMethod("https://" + HOST + "/trading/tabelc_4"); //$NON-NLS-1$ //$NON-NLS-2$ method.setFollowRedirects(true); method.setQueryString(new NameValuePair[] { new NameValuePair("USER", user), //$NON-NLS-1$ new NameValuePair("DEVAR", id), //$NON-NLS-1$ }); logger.debug(method.getURI().toString()); client.executeMethod(method); Parser parser = Parser.createParser(method.getResponseBodyAsString(), ""); //$NON-NLS-1$ NodeList list = parser.extractAllNodesThatMatch(new NodeClassFilter(TableRow.class)); for (SimpleNodeIterator iter = list.elements(); iter.hasMoreNodes();) { TableRow row = (TableRow) iter.nextNode(); if (row.getChildCount() == 23) { if (row.getChild(1) instanceof TableHeader) { continue; } String symbol = ""; //$NON-NLS-1$ String isin = ""; //$NON-NLS-1$ String description = ""; //$NON-NLS-1$ LinkTag link = (LinkTag) ((TableColumn) row.getChild(1)).getChild(1); int s = link.getText().indexOf("TITO="); //$NON-NLS-1$ if (s != -1) { s += 5; int e = link.getText().indexOf("&", s); //$NON-NLS-1$ if (e == -1) { e = link.getText().length(); } symbol = link.getText().substring(s, e); } description = link.getFirstChild().getText(); description = description.replaceAll("[\r\n]", " ").trim(); //$NON-NLS-1$ //$NON-NLS-2$ link = (LinkTag) ((TableColumn) row.getChild(5)).getChild(0); s = link.getText().indexOf("tlv="); //$NON-NLS-1$ if (s != -1) { s += 4; int e = link.getText().indexOf("&", s); //$NON-NLS-1$ if (e == -1) { e = link.getText().length(); } isin = link.getText().substring(s, e); } System.out.println(symbol + " " + isin + " (" + description + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } } catch (Exception e) { logger.error(e.toString(), e); } } }