├── FetchOptionsChain.java ├── IB Algo Flowchart.png ├── KillSwitch.java ├── LICENSE ├── LargePriceFeed.java ├── PennyPilot.csv ├── README.md ├── SimplePriceFeed.java ├── TickerList.csv ├── TradeStrategy.java ├── fetchOptionsChain ├── RequestOptionChain.java └── RequestOptionChainWrapper.java ├── largePriceFeed ├── RequestPriceData.java ├── RequestPriceWrapper.java └── WritePriceData.java ├── simplePriceFeed ├── RequestPriceData.java ├── RequestPriceWrapper.java └── WritePriceData.java └── tradeStrategy ├── FetchOrderStatus.java └── TradeStrategyWrapper.java /FetchOptionsChain.java: -------------------------------------------------------------------------------- 1 | import fetchOptionsChain.RequestOptionChainWrapper; 2 | import fetchOptionsChain.RequestOptionChain; 3 | 4 | import com.ib.client.Contract; 5 | import com.ib.client.EClientSocket; 6 | import com.ib.client.EWrapper; 7 | 8 | import java.io.BufferedReader; 9 | import java.io.FileReader; 10 | import java.io.IOException; 11 | import java.sql.Connection; 12 | import java.sql.DriverManager; 13 | import java.sql.PreparedStatement; 14 | import java.sql.ResultSet; 15 | import java.sql.SQLException; 16 | import java.util.Collections; 17 | import java.util.ArrayList; 18 | import java.util.HashMap; 19 | import java.util.List; 20 | import java.util.Map; 21 | 22 | 23 | // Read in TickerList.csv, a list of contracts to generate options chains from 24 | // TickerList.csv fields: Active (T/F) | symbol | secType | exchange | currency 25 | // | expiry | strike | right | multiplier 26 | // Read in PennyPilot.csv, a list of Penny Pilot tickers 27 | // Output option chain to IBAlgoSystem.MasterChainList 28 | 29 | public class FetchOptionsChain { 30 | private EClientSocket socket = null; 31 | public String delimiter = ","; 32 | public String delimiter_under = "_"; 33 | public String csvFile = "TickerList.csv"; 34 | public String PennyPilotFile = "PennyPilot.csv"; 35 | public String[] TickerList; 36 | public int counter_iter = 0; 37 | public double price = -1.0; 38 | public Connection sqlConnection = null; 39 | public PreparedStatement preparedStatement = null; 40 | public ResultSet resultSet = null; 41 | 42 | 43 | public void sqlClose() { 44 | try { 45 | if (resultSet != null) { 46 | resultSet.close(); 47 | } 48 | 49 | if (sqlConnection != null) { 50 | sqlConnection.close(); 51 | } 52 | } catch (Exception e) { 53 | } 54 | } 55 | 56 | 57 | public FetchOptionsChain() { 58 | Map PennyPilotMap = new HashMap<>(); 59 | boolean foundPennyTick; 60 | 61 | // load Penny Pilot Tickers 62 | List PennyPilotTickers = new ArrayList(); 63 | StringBuilder temp_ticker = new StringBuilder(""); 64 | try (BufferedReader br1 = new BufferedReader(new FileReader(PennyPilotFile))) { 65 | String input1; 66 | while ((input1 = br1.readLine()) != null) { 67 | if (!input1.split(delimiter)[0].equals(temp_ticker.toString())) { 68 | temp_ticker = new StringBuilder(input1.split(delimiter)[0]); 69 | PennyPilotTickers.add(temp_ticker.toString()); 70 | } 71 | } 72 | br1.close(); 73 | } catch (IOException e) { 74 | e.printStackTrace(); 75 | } 76 | Collections.sort(PennyPilotTickers); 77 | 78 | 79 | // find number of rows in TickerList 80 | int rows = 0; 81 | try (BufferedReader br2 = new BufferedReader(new FileReader(csvFile))) { 82 | String input2; 83 | while ((input2 = br2.readLine()) != null) { 84 | rows++; 85 | } 86 | br2.close(); 87 | } catch (IOException e) { 88 | e.printStackTrace(); 89 | } 90 | 91 | 92 | // write values of TickerList 93 | TickerList = new String[rows]; 94 | try (BufferedReader br3 = new BufferedReader(new FileReader(csvFile))) { 95 | String input3; 96 | int row_iter = 0; 97 | while ((input3 = br3.readLine()) != null) { 98 | TickerList[row_iter] = input3; 99 | row_iter++; 100 | } 101 | br3.close(); 102 | } catch (IOException e) { 103 | e.printStackTrace(); 104 | } 105 | 106 | 107 | // connect to sql, update counter 108 | try { 109 | Class.forName("com.mysql.jdbc.Driver"); 110 | sqlConnection = DriverManager.getConnection( 111 | "jdbc:mysql://localhost/IBAlgoSystem?user=user&password=pw"); 112 | preparedStatement = sqlConnection.prepareStatement( 113 | "UPDATE IBAlgoSystem.counter SET counter = 0"); 114 | preparedStatement.executeUpdate(); 115 | preparedStatement = sqlConnection.prepareStatement( 116 | "TRUNCATE TABLE IBAlgoSystem.MasterChainList"); 117 | preparedStatement.executeUpdate(); 118 | 119 | 120 | // write PennyPilotMap 121 | for (int i=0; i < TickerList.length; i++) { 122 | foundPennyTick = false; 123 | for (int j=0; j < PennyPilotTickers.size(); j++) { 124 | if (TickerList[i].split(delimiter)[1].equals(PennyPilotTickers.get(j))) { 125 | foundPennyTick = true; 126 | break; 127 | } 128 | } 129 | 130 | if (foundPennyTick) { 131 | PennyPilotMap.put(TickerList[i].split(delimiter)[1], "T"); 132 | } else { 133 | PennyPilotMap.put(TickerList[i].split(delimiter)[1], "F"); 134 | } 135 | } 136 | 137 | 138 | // connect to socket 139 | EWrapper requestOptionChainWrapper = new RequestOptionChainWrapper(sqlConnection); 140 | EClientSocket socket = new EClientSocket(requestOptionChainWrapper); 141 | socket.eConnect (null, 4002, 100); 142 | try { 143 | while (!(socket.isConnected())); 144 | } catch (Exception e) { 145 | } 146 | 147 | // submit a new contract for every request 148 | for (int i = 0; i < rows; i++) { 149 | String line = TickerList[i]; 150 | Contract cont = new Contract(); 151 | cont.m_symbol = line.split(delimiter)[1]; 152 | cont.m_secType = "OPT"; 153 | cont.m_exchange = "SMART"; 154 | cont.m_currency = line.split(delimiter)[4]; 155 | cont.m_multiplier = "100"; 156 | RequestOptionChain data = new RequestOptionChain(cont, socket, sqlConnection); 157 | } 158 | 159 | 160 | // check counter to disconnect socket 161 | preparedStatement = sqlConnection.prepareStatement( 162 | "SELECT counter FROM IBAlgoSystem.counter;"); 163 | resultSet = preparedStatement.executeQuery(); 164 | counter_iter = WriteInt(resultSet, "counter"); 165 | while (counter_iter < rows) { 166 | resultSet = preparedStatement.executeQuery(); 167 | counter_iter = WriteInt(resultSet, "counter"); 168 | } 169 | socket.eDisconnect(); 170 | 171 | } catch (Exception e) { 172 | e.printStackTrace(); 173 | } finally { 174 | sqlClose(); 175 | } 176 | } 177 | 178 | 179 | private int WriteInt(ResultSet resultSet, String column_name) throws SQLException { 180 | int output_counter = 0; 181 | while (resultSet.next()) { 182 | output_counter = resultSet.getInt(column_name); 183 | } 184 | return output_counter; 185 | } 186 | 187 | 188 | public static void main(String args[]) { 189 | try { 190 | FetchOptionsChain runProcess = new FetchOptionsChain(); 191 | } catch (Exception e) { 192 | e.printStackTrace (); 193 | } 194 | } 195 | } -------------------------------------------------------------------------------- /IB Algo Flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rediar/InteractiveBrokers-Algo-Trading-API/c1e0c3a54970ea50a5d3a22f91ec19e2eb864e28/IB Algo Flowchart.png -------------------------------------------------------------------------------- /KillSwitch.java: -------------------------------------------------------------------------------- 1 | import tradeStrategy.TradeStrategyWrapper; 2 | 3 | import com.ib.client.EClientSocket; 4 | import com.ib.client.EWrapper; 5 | 6 | import java.sql.Connection; 7 | import java.sql.DriverManager; 8 | import java.sql.PreparedStatement; 9 | import java.sql.ResultSet; 10 | 11 | 12 | // kills all active orders 13 | 14 | public class KillSwitch { 15 | public Connection sqlConnection = null; 16 | public PreparedStatement preparedStatement = null; 17 | public ResultSet resultSet = null; 18 | 19 | 20 | public KillSwitch () { 21 | 22 | // connect to SQL 23 | try { 24 | Class.forName("com.mysql.jdbc.Driver"); 25 | sqlConnection = DriverManager.getConnection( 26 | "jdbc:mysql://localhost/IBAlgoSystem?user=user&password=pw"); 27 | 28 | 29 | // connect to socket 30 | EWrapper tradeStrategyWrapper = new TradeStrategyWrapper(sqlConnection); 31 | EClientSocket socket = new EClientSocket(tradeStrategyWrapper); 32 | socket.eConnect("", 4002, 1000); 33 | try { 34 | while (!(socket.isConnected())); 35 | } catch (Exception e) { 36 | } 37 | 38 | 39 | // find outstanding active orders 40 | preparedStatement = sqlConnection.prepareStatement( 41 | "SELECT orderID FROM IBAlgoSystem.orderTracking WHERE " 42 | + "status <> 'Filled' AND status <> 'Cancelled' AND " 43 | + "status <> 'ApiCancelled' AND status <> 'Inactive';"); 44 | resultSet = preparedStatement.executeQuery(); 45 | 46 | // submit cancel request 47 | while (resultSet.next()) { 48 | int orderId = resultSet.getInt("orderID"); 49 | socket.cancelOrder(orderId); 50 | } 51 | 52 | // wait for all orders to cancel 53 | boolean ContinueProcess = false; 54 | preparedStatement = sqlConnection.prepareStatement( 55 | "SELECT COUNT(*) FROM IBAlgoSystem.orderTracking WHERE " 56 | + "status <> 'Filled' AND status <> 'Cancelled' AND " 57 | + "status <> 'ApiCancelled' AND status <> 'Inactive';"); 58 | while (!ContinueProcess) { 59 | resultSet = preparedStatement.executeQuery(); 60 | if (resultSet.getInt("COUNT(*)") == 0) { 61 | ContinueProcess = true; 62 | } 63 | } 64 | 65 | socket.eDisconnect(); 66 | 67 | } catch (Exception e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | 73 | public static void main (String args[]) { 74 | KillSwitch runProcess = new KillSwitch(); 75 | } 76 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LargePriceFeed.java: -------------------------------------------------------------------------------- 1 | import largePriceFeed.RequestPriceData; 2 | import largePriceFeed.RequestPriceWrapper; 3 | import largePriceFeed.WritePriceData; 4 | 5 | import com.ib.client.Contract; 6 | import com.ib.client.EClientSocket; 7 | import com.ib.client.EWrapper; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.FileReader; 11 | import java.io.IOException; 12 | import java.sql.Connection; 13 | import java.sql.DriverManager; 14 | import java.sql.PreparedStatement; 15 | import java.sql.ResultSet; 16 | import java.util.Date; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | 21 | // Read in IBAlgoSystem.MasterChainList - a list of options contracts to 22 | // receive live price streams from 23 | // The number of entries may exceed ib's feed limit (FEED_LIMIT) 24 | // This script divides the entries into smaller batches to submit to ib 25 | // Output prices to IBAlgoSystem.price 26 | 27 | public class LargePriceFeed { 28 | private EClientSocket socket = null; 29 | public String delimiter = ","; 30 | public String delimiter_under = "_"; 31 | public String TickerListCSVFile = "TickerList.csv"; 32 | public String[] TickerLines; 33 | public Map FileUpdated = new HashMap(); 34 | public long updateTime, dt_now; 35 | public boolean AllUpdated, running_updated; 36 | public int FEED_LIMIT = 100; 37 | public Connection sqlConnection = null; 38 | public PreparedStatement preparedStatement = null; 39 | public ResultSet resultSet = null; 40 | 41 | 42 | public LargePriceFeed () { 43 | int NUM_FEEDS = 0; 44 | 45 | // find NUM_FEEDS from 100 - rows of TickerList 46 | try (BufferedReader br3 = new BufferedReader(new FileReader(TickerListCSVFile))) { 47 | String input3; 48 | while((input3 = br3.readLine()) != null) { 49 | if (!input3.split(delimiter)[0].equals("active")) { 50 | NUM_FEEDS++; 51 | } 52 | } 53 | br3.close(); 54 | } catch (IOException e) { 55 | e.printStackTrace(); 56 | } 57 | 58 | // make sure NUM_FEEDS is sufficient 59 | if (NUM_FEEDS >= (FEED_LIMIT - 5)) { 60 | System.out.println("Not enough sockets for feed!"); 61 | 62 | } else { 63 | NUM_FEEDS = FEED_LIMIT - 5 - NUM_FEEDS; 64 | 65 | // connect to SQL 66 | try { 67 | Class.forName("com.mysql.jdbc.Driver"); 68 | sqlConnection = DriverManager.getConnection( 69 | "jdbc:mysql://localhost/IBAlgoSystem?user=user&password=pw"); 70 | 71 | // find number of rows in MasterChainList 72 | preparedStatement = sqlConnection.prepareStatement( 73 | "SELECT COUNT(*) FROM IBAlgoSystem.MasterChainList;"); 74 | resultSet = preparedStatement.executeQuery(); 75 | int rows = resultSet.getInt("COUNT(*)"); 76 | 77 | 78 | // write values of MasterChainList to TickerLines, dummy price 79 | // TickerLines format: active, symbol, secType, exchange, 80 | // currency, expiry, strike, right, multiplier, pennyPilot, 81 | // moneyness 82 | TickerLines = new String[rows]; 83 | preparedStatement = sqlConnection.prepareStatement( 84 | "SELECT * FROM IBAlgoSystem.MasterChainList"); 85 | resultSet = preparedStatement.executeQuery(); 86 | 87 | int row_iter = 0; 88 | while (resultSet.next()) { 89 | String symbol = resultSet.getString("symbol"); 90 | String exchange = resultSet.getString("exchange"); 91 | String currency = resultSet.getString("currency"); 92 | String expiry = resultSet.getString("expiry"); 93 | double strike = resultSet.getDouble("strike"); 94 | String right = resultSet.getString("callorput"); 95 | String multiplier = resultSet.getString("multiplier"); 96 | String pennyPilot = resultSet.getString("pennyPilot"); 97 | String moneyness = resultSet.getString("moneyness"); 98 | double bid = -1.0; 99 | double ask = -1.0; 100 | 101 | // delete previous entry 102 | preparedStatement = sqlConnection.prepareStatement( 103 | "DELETE FROM IBAlgoSystem.price WHERE symbol = '" 104 | + symbol + "' and secType = 'OPT' and currency = '" 105 | + currency + "' and expiry = '" + expiry + 106 | "' and strike = " + Double.toString(strike) + 107 | " and callorput = '" + right + "' and multiplier = '" 108 | + multiplier + "';"); 109 | preparedStatement.executeUpdate(); 110 | 111 | // write new entry 112 | preparedStatement = sqlConnection.prepareStatement( 113 | "INSERT INTO IBAlgoSystem.price (entry, symbol, " 114 | + "secType, currency, expiry, strike, callorput, " 115 | + "multiplier, bid, ask, last, close, bugCounter, " 116 | + "updateTime) VALUES (default,'" + symbol + 117 | "', 'OPT', '" + currency + "', '" + expiry + "', " 118 | + Double.toString(strike) + ", '" + right + "', '" 119 | + multiplier + "', 0.0, 0.01, -1.0, -1.0, 0, 0);"); 120 | preparedStatement.executeUpdate(); 121 | } 122 | 123 | 124 | // divide the list of names into batches of NUM_FEEDS 125 | int num_batches = rows/NUM_FEEDS + 1; 126 | 127 | 128 | // connect to socket 129 | EWrapper requestPriceWrapper = new RequestPriceWrapper(); 130 | EClientSocket socket = new EClientSocket(requestPriceWrapper); 131 | 132 | 133 | // update prices by batch 134 | 135 | // connect to socket 136 | socket.eConnect(null, 4002, 101); 137 | try { 138 | while (!(socket.isConnected())); 139 | } catch (Exception e) { 140 | } 141 | 142 | // add while loop to make perpeptual 143 | while (true) { 144 | for (int i=0; i < num_batches; i++) { 145 | 146 | // send price feed requests 147 | for (int j=0; j < NUM_FEEDS; j++) { 148 | if ((i*NUM_FEEDS + j) < rows) { 149 | // submit a new contract for every request 150 | String line = TickerLines[i*NUM_FEEDS + j]; 151 | Contract cont = new Contract(); 152 | cont.m_symbol = line.split(delimiter_under)[1]; 153 | cont.m_secType = line.split(delimiter_under)[2]; 154 | // cont.m_exchange = line.split(delimiter)[3]; 155 | cont.m_exchange = "SMART"; 156 | cont.m_currency = line.split(delimiter_under)[4]; 157 | cont.m_expiry = line.split(delimiter_under)[5]; 158 | cont.m_strike = Double.parseDouble(line.split(delimiter_under)[6]); 159 | cont.m_right = line.split(delimiter_under)[7]; 160 | cont.m_multiplier = line.split(delimiter_under)[8]; 161 | 162 | FileUpdated.put(i*NUM_FEEDS + j, false); 163 | 164 | RequestPriceData data = new RequestPriceData(cont, 165 | true, socket, sqlConnection); 166 | } else { 167 | FileUpdated.put(i*NUM_FEEDS + j, true); 168 | } 169 | } 170 | 171 | 172 | // check price entry is updated to continue 173 | AllUpdated = false; 174 | while (!AllUpdated) { 175 | for (int j=0; j < NUM_FEEDS; j++) { 176 | if (!FileUpdated.get(i*NUM_FEEDS + j)) { 177 | String line = TickerLines[i*NUM_FEEDS + j]; 178 | String symbol = line.split(delimiter_under)[1]; 179 | String exchange = line.split(delimiter_under)[3]; 180 | String currency = line.split(delimiter_under)[4]; 181 | String expiry = line.split(delimiter_under)[5]; 182 | double strike = Double.parseDouble(line.split(delimiter_under)[6]); 183 | String right = line.split(delimiter_under)[7]; 184 | String multiplier = line.split(delimiter_under)[8]; 185 | 186 | preparedStatement = sqlConnection.prepareStatement( 187 | "SELECT updateTime FROM IBAlgoSystem.price WHERE symbol = '" 188 | + symbol + "' and secType = 'OPT' and currency = '" 189 | + currency + "' and expiry = '" + expiry 190 | + "' and strike = " + Double.toString(strike) 191 | + " and callorput = '" + right 192 | + "' and multiplier = '" + multiplier + "';"); 193 | resultSet = preparedStatement.executeQuery(); 194 | while (resultSet.next()) { 195 | updateTime = resultSet.getLong("updateTime"); 196 | } 197 | 198 | // check the last (last updated field) is actually updated, and within 5*NUM_FEEDS secs 199 | if ((fetchPrice.FetchSTKPrice(symbol, "USD", sqlConnection)[2] > -0.01) && 200 | (((new Date()).getTime() - updateTime) < 5*NUM_FEEDS*1000)) { 201 | FileUpdated.put(i*NUM_FEEDS + j, true); 202 | } 203 | } 204 | } 205 | 206 | for (int j=0; j < NUM_FEEDS; j++) { 207 | running_updated = true; 208 | if (!FileUpdated.get(i*NUM_FEEDS + j)) { 209 | running_updated = false; 210 | break; 211 | } 212 | } 213 | if (running_updated) { 214 | AllUpdated = true; 215 | } 216 | } 217 | 218 | // pause for 1 sec between each batch 219 | dt_now = (new Date()).getTime(); 220 | while (((new Date()).getTime() - dt_now) < (1*1000)); 221 | } 222 | 223 | // pause for 1 min between each loop 224 | if (num_batches < 60) { 225 | dt_now = (new Date()).getTime(); 226 | while (((new Date()).getTime() - dt_now) < (60*1000)); 227 | } 228 | } 229 | } catch (Exception e) { 230 | e.printStackTrace(); 231 | } 232 | } 233 | } 234 | 235 | 236 | public static void main (String args[]) { 237 | try { 238 | LargePriceFeed runProcess = new LargePriceFeed(); 239 | } catch (Exception e) { 240 | e.printStackTrace (); 241 | } 242 | } 243 | } -------------------------------------------------------------------------------- /PennyPilot.csv: -------------------------------------------------------------------------------- 1 | A AAL AAPL ABBV ABT ABX ADBE ADM ADSK AEM AET AFL AGN AGNC AGO AIG AKAM AKS ALL AMAT AMD AMED AMGN AMRN AMZN ANF ANTM APA APC ARNA ARNC ASHR ATVI AUY AXP BA BABA BAC BAX BBBY BBD BBRY BBT BBY BCRX BHI BHP BIDU BK BMY BP BPOP BRCD BRKB BSX BX C CAT CBS CELG CENX CF CHK CI CIEN CIT CL CLF CMA CMCSA CNX COF COP COST COTY CREE CRM CSCO CSX CTIC CVS CVX CX DAL DB DD DDD DE DHI DIA DIS DO DOW DVN DXJ EA EBAY EEM EFA EOG ESRX ETE ETFC EWJ EWT EWW EWY EWZ F FAS FAZ FB FCX FDX FEYE FFIV FH FIS FIT FITB FLEX FSLR FXE FXI FXP GDX GDXJ GE GFI GG GGP GILD GIS GLD GLW GM GME GNW GPRO GPS GRMN GRPN GS HAL HBAN HD HES HIG HL HLF HOG HON HPQ HSBC HSY HYG IBM IBN INTC IP IWM IYR JCI JCP JD JNJ JNPR JPM JWN KBH KCG KEY KGC KMI KO KRE LEN LLY LNC LNG LOW LULU LVS M MA MBI MCD MCO MDLZ MDT MET MGM MMM MNKD MNX MO MON MOS MRK MRO MRVL MS MSFT MSI MT MTG MU MYL NBR NE NEM NFLX NKE NLY NOK NOV NQ NTAP NUE NUGT NVDA ODP OIH ORCL OXY P PBR PEP PFE PG PHM PLUG PM PNC POT PRU PYPL QCOM QID QLD QQQ RAD RCL RF RIG RMBS RSX RTN S SBUX SDS SEED SHLD SINA SIRI SKF SLB SLM SLV SLW SO SPG SPWR SPY SRPT SRS SSO STI STT STX SU SVXY SWN SYMC T TBT TECK TEVA TGT TIF TLT TM TMUS TNA TSLA TSO TWLO TWTR TWX TXN TXT TZA UAA UAL UNG UNH UNP UPS URE USB USO UTX UUP UVXY UYG V VALE VIAV VLO VOD VRSN VRX VVUS VXX VZ WBA WDC WFC WFM WFT WHR WIN WLL WMB WMT WYNN X XBI XHB XL XLB XLE XLF XLI XLK XLNX XLP XLU XLV XLY XME XOM XOP XRT XRX YHOO YRCW YUM ZION ZNGA -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # InteractiveBrokers Algo Trading API 2 | This Java/MySQL framework implements the Interactive Brokers API for algorithmic trading. Included are all essential components to support a basic trading execution system: live price feed, handling for IB price quote limits, order tracking system, margin tracking system, handling for order submission and execution, option chain information request, and kill switches. A system based on this framework, with additional custom modules and proprietary strategies is currently being used to profitably trade US equities and equity options 3 | - Requires either TWS or IB Gateway (desktop applications provided by IB) and IB Java API 9.71 (API library package). The API scripts initiate a live socket connection to the desktop TWS and IB Gateway application, which routes requests 4 | - Requires US Securities Snapshot and Futures Value Bundle ($10/month), US Equity and Options Add-On Streaming Bundle ($4.95/month) for live price feed. If solely using the framework for executing orders, then these add on costs are not necessary; it is possible to use another data source for live price feeds such as IEX, which is free 5 | - It's recommended to simultaneously run price feed and solely reading processes on an IB Gateway paper trading instance (port 4002 in the example) and trade execution/other writing processes on a TWS instance (port 7496 in the example) 6 | - API function documentation: http://interactivebrokers.github.io/tws-api/ 7 | ![Flowchart](https://github.com/rediar/InteractiveBrokers-Algo-System/blob/master/IB%20Algo%20Flowchart.png) 8 | 9 | # Setup instructions 10 | ### Set up MySQL database ### 11 | Set up the following tables: 12 | 13 | Price: 14 | - IBAlgoSystem.price: symbol (VARCHAR(10)), secType (VARCHAR(10)), currency (VARCHAR(3)), expiry (VARCHAR(8)), strike (DOUBLE), callorput (VARCHAR(1)), multiplier (VARCHAR(10)), bid (DOUBLE), ask (DOUBLE), last (DOUBLE), close (DOUBLE), bugCounter (INT), updateTime (BIGINT) 15 | 16 | Option details: 17 | - IBAlgoSystem.MasterChainList: entry (INT), active (VARCHAR(1)), symbol (VARCHAR(10)), secType (VARCHAR(10)), exchange (VARCHAR(20)), currency (VARCHAR(3)), expiry (VARCHAR(8)), strike (DOUBLE), callorput (VARCHAR(1)), multiplier (VARCHAR(10)), pennyPilot (VARCHAR(1)), moneyness (VARCHAR(3)) 18 | 19 | Orders: 20 | - IBAlgoSystem.orderTracking: orderID (INT), status (VARCHAR(20)), filled (INT), remaining (INT), avgFillPrice (DOUBLE) 21 | 22 | Execution failure retry counter: 23 | - IBAlgoSystem.counter: counterID (INT) 24 | 25 | Cash, margin and risk balance: 26 | - IBAlgoSystem.margin: AccruedCash (DOUBLE), AvailableFunds (DOUBLE), BuyingPower (DOUBLE), Cushion (DOUBLE), EquityWithLoanValue (DOUBLE), ExcessLiquidity (DOUBLE), FullAvailableFunds (DOUBLE), FullExcessLiquidity (DOUBLE), FullInitMarginReq (DOUBLE), FullMaintMarginReq (DOUBLE), GrossPositionValue (DOUBLE), InitMarginReq (DOUBLE), LookAheadAvailableFunds (DOUBLE), LookAheadExcessLiquidity (DOUBLE), LookAheadInitMarginReq (DOUBLE), LookAheadMaintMarginReq (DOUBLE), LookAheadNextChange (DOUBLE), MaintMarginReq (DOUBLE), NetLiquidation (DOUBLE), TotalCashValue (DOUBLE) 27 | 28 | # Module descriptions 29 | 30 | ### SimplePriceFeed ### 31 | Read in TickerList.csv - a presaved list of contracts to receive live price feeds from. Here, a contract is defined as either a specific option, or stock 32 | - TickerList.csv fields: Active (T/F) | symbol | secType | exchange | currency | expiry | strike | right | multiplier 33 | - Output prices to the IBAlgoSystem.price MySQL table 34 | 35 | ### LargePriceFeed ### 36 | Read in IBAlgoSystem.MasterChainList - a list of options contracts to receive live price feeds from 37 | - The number of entries may exceed IB's feed limit (FEED_LIMIT). In that case, this script divides the entries into smaller batches to submit to IB 38 | - Output prices to IBAlgoSystem.price MySQL table 39 | 40 | ### FetchOptionsChain ### 41 | Read in TickerList.csv, a presaved list of contracts to receive live price feeds from. Here, a contract is defined as either a specific option, or stock 42 | - TickerList.csv fields: Active (T/F) | symbol | secType | exchange | currency | expiry | strike | right | multiplier 43 | Read in PennyPilot.csv, a presaved list of Penny Pilot tickers 44 | - Output option chain to IBAlgoSystem.MasterChainList MySQL table 45 | 46 | ### TradeStrategy ### 47 | Template to implement trade strategies - call price feed, submit order execution requests, manage orders and risk 48 | - Output order management to IBAlgoSystem.orderTracking MySQL table 49 | - Output margin management to IBAlgoSystem.margin MySQL table 50 | 51 | ### KillSwitch ### 52 | Kills all active orders 53 | 54 | # Simple walkthrough description 55 | 56 | ### Receive price feed ### 57 | 1. Start an IB Gateway instance on port 4002 (or custom defined port number) 58 | 2. Define the contracts to receive stock and/or option price feeds for in TickerList.csv 59 | 3. Execute SimplePriceFeed to start price feeds for contracts in TickerList.csv 60 | 4. If TickerList.csv contains only stock tickers, execute FetchOptionsChain to generate the option chain for those tickers 61 | 5. Execute LargePriceFeed to start price feeds for option chains 62 | 6. Restart SimplePriceFeed or LargePriceFeed if problems occur 63 | 64 | ### Execute trade strategy ### 65 | 1. Start a TWS instance on port 7496 (or custom defined port number) 66 | 2. Execute TradeStrategy 67 | 68 | ### Trigger KillSwitch ### 69 | In event of emergency only: 70 | 1. Terminate TradeStrategy 71 | 2. Execute KillSwitch to remove outstanding orders 72 | 73 | Note the KillSwith does not impact SimplePriceFeed or LargePriceFeed (price feed) 74 | -------------------------------------------------------------------------------- /SimplePriceFeed.java: -------------------------------------------------------------------------------- 1 | import simplePriceFeed.RequestPriceWrapper; 2 | import simplePriceFeed.RequestPriceData; 3 | import simplePriceFeed.WritePriceData; 4 | 5 | import com.ib.client.Contract; 6 | import com.ib.client.EClientSocket; 7 | import com.ib.client.EWrapper; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.FileReader; 11 | import java.io.IOException; 12 | import java.sql.Connection; 13 | import java.sql.DriverManager; 14 | import java.sql.PreparedStatement; 15 | 16 | 17 | // Read in TickerList.csv - a list of contracts to receive live price streams from 18 | // TickerList.csv fields: Active (T/F) | symbol | secType | exchange | currency 19 | // | expiry | strike | right | multiplier 20 | // Output prices to IBAlgoSystem.price 21 | 22 | public class SimplePriceFeed { 23 | public Connection sqlConnection = null; 24 | public PreparedStatement preparedStatement = null; 25 | 26 | 27 | public SimplePriceFeed() throws Exception { 28 | // read in TickerList.csv 29 | String csvFile = "TickerList.csv"; 30 | String delimiter = ","; 31 | 32 | // find number of rows in TickerList 33 | int rows = 0; 34 | try (BufferedReader br1 = new BufferedReader(new FileReader(csvFile))) { 35 | String input1; 36 | while ((input1 = br1.readLine()) != null) { 37 | if (input1.split(delimiter)[0].equals("T")) { 38 | rows++; 39 | } 40 | } 41 | br1.close(); 42 | } catch (IOException e) { 43 | e.printStackTrace(); 44 | } 45 | 46 | 47 | // connect to IBAlgoSystem.price, clear previous data 48 | Class.forName("com.mysql.jdbc.Driver"); 49 | sqlConnection = DriverManager.getConnection( 50 | "jdbc:mysql://localhost/IBAlgoSystem?user=user&password=pw"); 51 | // this line assumes TickerList.csv only contains stocks (secType = STK) 52 | preparedStatement = sqlConnection.prepareStatement( 53 | "DELETE FROM IBAlgoSystem.price WHERE secType = 'STK'"); 54 | preparedStatement.executeUpdate(); 55 | 56 | 57 | // write dummy values of TickerList to IBAlgoSystem.price 58 | String[] TickerLines = new String[rows]; 59 | try (BufferedReader br2 = new BufferedReader(new FileReader(csvFile))) { 60 | String input2; 61 | int row_iter = 0; 62 | while ((input2 = br2.readLine()) != null) { 63 | if (input2.split(delimiter)[0].equals("T")) { 64 | if (input2.split(delimiter)[2].equals("STK")) { 65 | preparedStatement = sqlConnection.prepareStatement( 66 | "INSERT INTO IBAlgoSystem.price (entry, symbol, " 67 | + "secType, currency, bid, ask, last, close, " 68 | + "bugCounter, updateTime) VALUES (default,'" 69 | + input2.split(delimiter)[1] + "','" 70 | + input2.split(delimiter)[2] + "','" 71 | + input2.split(delimiter)[4] 72 | + "', -1.0, -1.0, -1.0, -1.0, 0, 0)"); 73 | } else if (input2.split(delimiter)[2].equals("OPT")) { 74 | preparedStatement = sqlConnection.prepareStatement( 75 | "DELETE FROM IBAlgoSystem.price WHERE symbol = '" 76 | + input2.split(delimiter)[1] + 77 | "' and secType = 'OPT' and currency = '" 78 | + input2.split(delimiter)[4] + "' and expiry = '" 79 | + input2.split(delimiter)[5] + "' and strike = " 80 | + input2.split(delimiter)[6] + " and callorput = '" 81 | + input2.split(delimiter)[7] 82 | + "' and multiplier = '" 83 | + input2.split(delimiter)[8] + "';"); 84 | preparedStatement.executeUpdate(); 85 | 86 | preparedStatement = sqlConnection.prepareStatement( 87 | "INSERT INTO IBAlgoSystem.price (entry, symbol, " 88 | + "secType, currency, expiry, strike, callorput, " 89 | + "multiplier, bid, ask, last, close, bugCounter, " 90 | + "updateTime) VALUES (default,'" + 91 | input2.split(delimiter)[1] + "','" 92 | + input2.split(delimiter)[2] + "','" 93 | + input2.split(delimiter)[4] + "','" 94 | + input2.split(delimiter)[5] + "'," 95 | + input2.split(delimiter)[6] +",'" 96 | + input2.split(delimiter)[7] + "','" 97 | + input2.split(delimiter)[8] 98 | + "', -1.0, -1.0, -1.0, -1.0, 0, 0)"); 99 | } 100 | preparedStatement.executeUpdate(); 101 | 102 | TickerLines[row_iter] = input2; 103 | row_iter++; 104 | } 105 | } 106 | br2.close(); 107 | } catch (IOException e) { 108 | e.printStackTrace(); 109 | } 110 | 111 | // connect to IB socket 112 | EWrapper requestPriceWrapper = new RequestPriceWrapper(); 113 | EClientSocket socket = new EClientSocket(requestPriceWrapper); 114 | socket.eConnect("", 4002, 0); 115 | try { 116 | while (!(socket.isConnected())); 117 | } catch (Exception e) { 118 | } 119 | 120 | // request live data setting 121 | socket.reqMarketDataType(1); 122 | 123 | // submit a new contract for every request 124 | for (int i = 0; i < rows; i++) { 125 | String line = TickerLines[i]; 126 | Contract cont = new Contract(); 127 | cont.m_symbol = line.split(delimiter)[1]; 128 | cont.m_secType = line.split(delimiter)[2]; 129 | cont.m_exchange = line.split(delimiter)[3]; 130 | cont.m_currency = line.split(delimiter)[4]; 131 | if (cont.m_secType.equals("OPT")) { 132 | cont.m_expiry = line.split(delimiter)[5]; 133 | cont.m_strike = Double.parseDouble(line.split(delimiter)[6]); 134 | cont.m_right = line.split(delimiter)[7]; 135 | cont.m_multiplier = line.split(delimiter)[8]; 136 | } 137 | RequestPriceData data = new RequestPriceData(cont, socket, 138 | sqlConnection); 139 | } 140 | } 141 | 142 | public static void main(String[] args) { 143 | try { 144 | SimplePriceFeed runProcess = new SimplePriceFeed(); 145 | } catch (Exception e) { 146 | e.printStackTrace(); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /TickerList.csv: -------------------------------------------------------------------------------- 1 | active,symbol,secType,exchange,currency,expiry,strike,right,multiplier T,AMZN,STK,ISLAND,USD,,,, T,GOOG,STK,ISLAND,USD,,,, -------------------------------------------------------------------------------- /TradeStrategy.java: -------------------------------------------------------------------------------- 1 | import tradeStrategy.FetchOrderStatus; 2 | import tradeStrategy.TradeStrategyWrapper; 3 | 4 | import com.ib.client.Contract; 5 | import com.ib.client.ContractDetails; 6 | import com.ib.client.EClientSocket; 7 | import com.ib.client.EWrapper; 8 | import com.ib.client.Execution; 9 | import com.ib.client.Order; 10 | import com.ib.client.OrderState; 11 | import com.ib.client.TagValue; 12 | import com.ib.client.CommissionReport; 13 | import com.ib.client.UnderComp; 14 | 15 | import java.sql.Connection; 16 | import java.sql.DriverManager; 17 | import java.sql.PreparedStatement; 18 | import java.sql.ResultSet; 19 | 20 | 21 | // template to implement trade strategies 22 | 23 | public class TradeStrategy { 24 | public Connection sqlConnection = null; 25 | public PreparedStatement preparedStatement = null; 26 | public ResultSet resultSet = null; 27 | 28 | 29 | public TradeStrategy () { 30 | 31 | // connect to SQL 32 | try { 33 | Class.forName("com.mysql.jdbc.Driver"); 34 | sqlConnection = DriverManager.getConnection( 35 | "jdbc:mysql://localhost/IBAlgoSystem?user=user&password=pw"); 36 | 37 | 38 | // connect to socket 39 | EWrapper tradeStrategyWrapper = new TradeStrategyWrapper(); 40 | EClientSocket socket = new EClientSocket(tradeStrategyWrapper); 41 | socket.eConnect("", 7496, 1000); 42 | try { 43 | while (!(socket.isConnected())); 44 | } catch (Exception e) { 45 | } 46 | 47 | 48 | // load account summary 49 | socket.reqAccountSummary(7496, "All", "NetLiquidation," 50 | + "TotalCashValue, SettledCash, AccruedCash, BuyingPower," 51 | + "EquityWithLoanValue, PreviousEquityWithLoanValue," 52 | + "GrossPositionValue, ReqTEquity, ReqTMargin, SMA, " 53 | + "InitMarginReq, MaintMarginReq, AvailableFunds," 54 | + "ExcessLiquidity, Cushion, FullInitMarginReq," 55 | + "FullMaintMarginReq, FullAvailableFunds, FullExcessLiquidity," 56 | + "LookAheadNextChange, LookAheadInitMarginReq," 57 | + "LookAheadMaintMarginReq, LookAheadAvailableFunds," 58 | + "LookAheadExcessLiquidity, HighestSeverity, Leverage"); 59 | 60 | 61 | // Here, call core functions to fetch prices, submit orders, manage 62 | // margin limit, etc. 63 | 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | 69 | 70 | public static void main (String args[]) { 71 | TradeStrategy runProcess = new TradeStrategy(); 72 | } 73 | } -------------------------------------------------------------------------------- /fetchOptionsChain/RequestOptionChain.java: -------------------------------------------------------------------------------- 1 | package fetchOptionsChain; 2 | 3 | import com.ib.client.Contract; 4 | import com.ib.client.EClientSocket; 5 | import java.sql.Connection; 6 | 7 | 8 | public class RequestOptionChain { 9 | final Contract cont; 10 | private final EClientSocket socket; 11 | private final Connection sqlConnection; 12 | 13 | private static int nextId = 1; 14 | private final int myId; 15 | 16 | public RequestOptionChain(Contract cont, EClientSocket socket, 17 | Connection sqlConnection) { 18 | this.cont = cont; 19 | this.socket = socket; 20 | this.sqlConnection = sqlConnection; 21 | myId = nextId++; 22 | socket.requestOptionChainWrapper(); 23 | reqOptionData(); 24 | } 25 | 26 | private void reqOptionData() { 27 | socket.reqContractDetails(myId, cont); 28 | } 29 | } -------------------------------------------------------------------------------- /fetchOptionsChain/RequestOptionChainWrapper.java: -------------------------------------------------------------------------------- 1 | package fetchOptionsChain; 2 | 3 | import com.ib.client.CommissionReport; 4 | import com.ib.client.Contract; 5 | import com.ib.client.ContractDetails; 6 | import com.ib.client.EWrapper; 7 | import com.ib.client.Execution; 8 | import com.ib.client.Order; 9 | import com.ib.client.OrderState; 10 | import com.ib.client.TickType; 11 | import com.ib.client.UnderComp; 12 | 13 | import java.sql.Connection; 14 | import java.sql.PreparedStatement; 15 | import java.sql.ResultSet; 16 | import java.sql.Statement; 17 | import java.sql.SQLException; 18 | 19 | 20 | public class RequestOptionChainWrapper implements EWrapper{ 21 | private final Connection sqlConnection; 22 | private Statement statement = null; 23 | private PreparedStatement preparedStatement = null; 24 | private ResultSet resultSet = null; 25 | 26 | public int counter_iter; 27 | 28 | public RequestOptionChainWrapper(Connection sqlConnection) { 29 | this.sqlConnection = sqlConnection; 30 | } 31 | 32 | public double outputSQLDouble(ResultSet resultSet, String output_field) throws SQLException { 33 | Double output_value = -1.0; 34 | while (resultSet.next()) { 35 | output_value = resultSet.getDouble(output_field); 36 | } 37 | return output_value; 38 | } 39 | 40 | public int outputSQLInt(ResultSet resultSet, String output_field) throws SQLException { 41 | int output_value = -1; 42 | while (resultSet.next()) { 43 | output_value = resultSet.getInt(output_field); 44 | } 45 | return output_value; 46 | } 47 | 48 | 49 | public void contractDetails(int reqId, ContractDetails contractDetails) { 50 | try { 51 | Contract contract = contractDetails.m_summary; 52 | 53 | // write to MasterChainList 54 | preparedStatement = sqlConnection.prepareStatement("INSERT INTO " 55 | + "IBAlgoSystem.MasterChainList VALUES (default, 'T', '" 56 | + contract.m_symbol + "', '" + contract.m_secType + "', '" 57 | + contract.m_exchange + "', '" + contract.m_currency + "', '" 58 | + contract.m_expiry + "', " 59 | + Double.toString(contract.m_strike) + ", '" 60 | + contract.m_right + "', '" + contract.m_multiplier 61 | + "', 'F', 'OTM');"); 62 | preparedStatement.executeUpdate(); 63 | 64 | } catch (Exception e) { 65 | e.printStackTrace(); 66 | } 67 | } 68 | 69 | public void contractDetailsEnd(int reqId) { 70 | try { 71 | // update counter 72 | statement = sqlConnection.createStatement(); 73 | resultSet = statement.executeQuery( 74 | "SELECT counter FROM misc.counter;"); 75 | counter_iter = outputSQLInt(resultSet, "counter"); 76 | 77 | counter_iter++; 78 | 79 | preparedStatement = sqlConnection.prepareStatement( 80 | "UPDATE misc.counter SET counter = " 81 | + Integer.toString(counter_iter) + ";"); 82 | preparedStatement.executeUpdate(); 83 | } catch (Exception e) { 84 | e.printStackTrace(); 85 | } 86 | } 87 | 88 | public void tickPrice(int tickerId, int field, double price, 89 | int canAutoExecute) { 90 | } 91 | 92 | public void execDetails(int reqId, Contract contract, Execution execution) { 93 | } 94 | 95 | public void bondContractDetails(int reqId, ContractDetails contractDetails) { 96 | } 97 | 98 | public void fundamentalData(int reqId, String data) { 99 | } 100 | 101 | public void bondContractDetails(ContractDetails contractDetails) { 102 | } 103 | 104 | public void currentTime(long time) { 105 | } 106 | 107 | public void displayGroupList(int requestId, String contraftInfo) { 108 | } 109 | 110 | public void displayGroupUpdated(int requestId, String contractInfo) { 111 | } 112 | 113 | public void verifyCompleted(boolean completed, String contractInfo) { 114 | } 115 | 116 | public void verifyMessageAPI(String message) { 117 | } 118 | 119 | public void execDetailsEnd(int reqId) { 120 | } 121 | 122 | public void historicalData(int reqId, String date, double open, double high, 123 | double low, double close, int volume, int count, double WAP, 124 | boolean hasGaps) { 125 | } 126 | 127 | public void managedAccounts(String accountsList) { 128 | } 129 | 130 | public void commissionReport(CommissionReport cr) { 131 | } 132 | 133 | public void position(String account, Contract contract, int pos, 134 | double avgCost) { 135 | } 136 | 137 | public void positionEnd() { 138 | } 139 | 140 | public void accountSummary(int reqId, String account, String tag, 141 | String value, String currency) { 142 | } 143 | 144 | public void accountSummaryEnd(int reqId) { 145 | } 146 | 147 | public void accountDownloadEnd(String accountName) { 148 | } 149 | 150 | public void openOrder(int orderId, Contract contract, Order order, 151 | OrderState orderState) { 152 | } 153 | 154 | public void openOrderEnd() { 155 | } 156 | 157 | public void orderStatus(int orderId, String status, int filled, 158 | int remaining, double avgFillPrice, int permId, int parentId, 159 | double lastFillPrice, int clientId, String whyHeld) { 160 | } 161 | 162 | public void receiveFA (int faDataType, String xml) { 163 | } 164 | 165 | public void scannerData(int reqId, int rank, ContractDetails contractDetails, 166 | String distance, String benchmark, String projection, String legsStr) { 167 | } 168 | 169 | public void scannerDataEnd(int reqId) { 170 | } 171 | 172 | public void scannerParameters(String xml) { 173 | } 174 | 175 | public void tickEFP(int symbolId, int tickType, double basisPoints, 176 | String formattedBasisPoints, double impliedFuture, int holdDays, 177 | String futureExpiry, double dividendImpact, double dividendsToExpiry) { 178 | } 179 | 180 | public void tickGeneric(int symbolId, int tickType, double value) { 181 | } 182 | 183 | public void tickOptionComputation( int tickerId, int field, 184 | double impliedVol, double delta, double optPrice, double pvDividend, 185 | double gamma, double vega, double theta, double undPrice) { 186 | } 187 | 188 | public void deltaNeutralValidation(int reqId, UnderComp underComp) { 189 | } 190 | 191 | public void updateAccountTime(String timeStamp) { 192 | } 193 | 194 | public void updateAccountValue(String key, String value, String currency, 195 | String accountName) { 196 | } 197 | 198 | public void updateMktDepth(int symbolId, int position, int operation, 199 | int side, double price, int size) { 200 | } 201 | 202 | public void updateMktDepthL2(int symbolId, int position, String marketMaker, 203 | int operation, int side, double price, int size) { 204 | } 205 | 206 | public void updateNewsBulletin(int msgId, int msgType, String message, 207 | String origExchange) { 208 | } 209 | 210 | public void updatePortfolio(Contract contract, int position, 211 | double marketPrice, double marketValue, double averageCost, 212 | double unrealizedPNL, double realizedPNL, String accountName) { 213 | } 214 | 215 | public void marketDataType(int reqId, int marketDataType) { 216 | } 217 | 218 | public void tickSnapshotEnd(int tickerId) { 219 | } 220 | 221 | public void connectionClosed() { 222 | } 223 | 224 | public void realtimeBar(int reqId, long time, double open, double high, 225 | double low, double close, long volume, double wap, int count) { 226 | } 227 | 228 | public void tickSize(int orderId, int field, int size) { 229 | } 230 | 231 | public void tickString(int orderId, int tickType, String value) { 232 | } 233 | 234 | public void error(Exception e) { 235 | e.printStackTrace (); 236 | } 237 | 238 | public void error(String str) { 239 | System.err.println (str); 240 | } 241 | 242 | public void error(int id, int errorCode, String errorMsg) { 243 | System.err.println ("error: " + id + "," + errorCode + "," + errorMsg); 244 | } 245 | 246 | public void nextValidId (int orderId) { 247 | } 248 | } -------------------------------------------------------------------------------- /largePriceFeed/RequestPriceData.java: -------------------------------------------------------------------------------- 1 | package largePriceFeed; 2 | 3 | import com.ib.client.Contract; 4 | import com.ib.client.EClientSocket; 5 | 6 | import java.sql.Connection; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | 11 | public class RequestPriceData { 12 | final Contract cont; 13 | final boolean snapshot; 14 | private final EClientSocket socket; 15 | private final WritePriceData writePriceData; 16 | private final Connection sqlConnection; 17 | 18 | private static int nextId = 1; 19 | private final int myId; 20 | 21 | List bidPrices = new ArrayList<>(); 22 | List askPrices = new ArrayList<>(); 23 | List lastPrices = new ArrayList<>(); 24 | List closePrices = new ArrayList<>(); 25 | double bidPrice = -1.0; 26 | double askPrice = -1.0; 27 | double lastPrice = -1.0; 28 | double closePrice = -1.0; 29 | 30 | public RequestPriceData(Contract cont, boolean snapshot, 31 | EClientSocket socket, Connection sqlConnection) { 32 | this.cont = cont; 33 | this.snapshot = snapshot; 34 | this.socket = socket; 35 | this.sqlConnection = sqlConnection; 36 | writePriceData = new WritePriceData(this, socket, sqlConnection); 37 | myId = nextId++; 38 | ((RequestPriceWrapper) socket.requestPriceWrapper()).dataMap.put(myId, this); 39 | reqData(); 40 | } 41 | 42 | private void reqData() { 43 | socket.reqMktData(myId, cont, "", snapshot, null); 44 | } 45 | 46 | // record bid price 47 | public void dataRecdBid(double inputPrice) { 48 | bidPrice = inputPrice; 49 | bidPrices.add(inputPrice); 50 | writePriceData.check(); 51 | } 52 | 53 | // record ask price 54 | public void dataRecdAsk(double inputPrice) { 55 | askPrice = inputPrice; 56 | askPrices.add(inputPrice); 57 | writePriceData.check(); 58 | } 59 | 60 | // record last price 61 | public void dataRecdLast(double inputPrice) { 62 | lastPrice = inputPrice; 63 | lastPrices.add(inputPrice); 64 | writePriceData.check(); 65 | } 66 | 67 | // record close price 68 | public void dataRecdClose(double inputPrice) { 69 | closePrice = inputPrice; 70 | closePrices.add(inputPrice); 71 | writePriceData.check(); 72 | } 73 | } -------------------------------------------------------------------------------- /largePriceFeed/RequestPriceWrapper.java: -------------------------------------------------------------------------------- 1 | package largePriceFeed; 2 | 3 | import com.ib.client.CommissionReport; 4 | import com.ib.client.Contract; 5 | import com.ib.client.ContractDetails; 6 | import com.ib.client.EWrapper; 7 | import com.ib.client.Execution; 8 | import com.ib.client.Order; 9 | import com.ib.client.OrderState; 10 | import com.ib.client.TickType; 11 | import com.ib.client.UnderComp; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | 17 | public class RequestPriceWrapper implements EWrapper{ 18 | public Map dataMap = new HashMap<>(); 19 | 20 | // reqMktData snapshots are received here 21 | public void tickPrice(int tickerId, int field, double price, 22 | int canAutoExecute) { 23 | 24 | // record bid price 25 | if (field == 1) { 26 | dataMap.get(tickerId).dataRecdBid(price); 27 | 28 | // record ask price 29 | } else if (field == 2) { 30 | dataMap.get(tickerId).dataRecdAsk(price); 31 | 32 | // record last price 33 | } else if (field == 4) { 34 | dataMap.get(tickerId).dataRecdLast(price); 35 | 36 | // record close price 37 | } else if (field == 9) { 38 | dataMap.get(tickerId).dataRecdClose(price); 39 | } 40 | } 41 | 42 | public void execDetails(int reqId, Contract contract, Execution execution) { 43 | } 44 | 45 | public void bondContractDetails(int reqId, ContractDetails contractDetails) { 46 | } 47 | 48 | public void contractDetails(int reqId, ContractDetails contractDetails) { 49 | } 50 | 51 | public void contractDetailsEnd(int reqId) { 52 | } 53 | 54 | public void fundamentalData(int reqId, String data) { 55 | } 56 | 57 | public void bondContractDetails(ContractDetails contractDetails) { 58 | } 59 | 60 | public void contractDetails(ContractDetails contractDetails) { 61 | } 62 | 63 | public void currentTime(long time) { 64 | } 65 | 66 | public void displayGroupList(int requestId, String contraftInfo) { 67 | } 68 | 69 | public void displayGroupUpdated(int requestId, String contractInfo) { 70 | } 71 | 72 | public void verifyCompleted(boolean completed, String contractInfo) { 73 | } 74 | 75 | public void verifyMessageAPI(String message) { 76 | } 77 | 78 | public void execDetailsEnd(int reqId) { 79 | } 80 | 81 | public void historicalData(int reqId, String date, double open, double high, 82 | double low, double close, int volume, int count, double WAP, 83 | boolean hasGaps) { 84 | } 85 | 86 | public void managedAccounts(String accountsList) { 87 | } 88 | 89 | public void commissionReport(CommissionReport cr) { 90 | } 91 | 92 | public void position(String account, Contract contract, int pos, 93 | double avgCost) { 94 | } 95 | 96 | public void positionEnd() { 97 | } 98 | 99 | public void accountSummary(int reqId, String account, String tag, 100 | String value, String currency) { 101 | } 102 | 103 | public void accountSummaryEnd(int reqId) { 104 | } 105 | 106 | public void accountDownloadEnd(String accountName) { 107 | } 108 | 109 | public void openOrder(int orderId, Contract contract, Order order, 110 | OrderState orderState) { 111 | } 112 | 113 | public void openOrderEnd() { 114 | } 115 | 116 | public void orderStatus(int orderId, String status, int filled, 117 | int remaining, double avgFillPrice, int permId, int parentId, 118 | double lastFillPrice, int clientId, String whyHeld) { 119 | } 120 | 121 | public void receiveFA (int faDataType, String xml) { 122 | } 123 | 124 | public void scannerData(int reqId, int rank, ContractDetails contractDetails, 125 | String distance, String benchmark, String projection, String legsStr) { 126 | } 127 | 128 | public void scannerDataEnd(int reqId) { 129 | } 130 | 131 | public void scannerParameters(String xml) { 132 | } 133 | 134 | public void tickEFP(int symbolId, int tickType, double basisPoints, 135 | String formattedBasisPoints, double impliedFuture, int holdDays, 136 | String futureExpiry, double dividendImpact, double dividendsToExpiry) { 137 | } 138 | 139 | public void tickGeneric(int symbolId, int tickType, double value) { 140 | } 141 | 142 | public void tickOptionComputation( int tickerId, int field, 143 | double impliedVol, double delta, double optPrice, double pvDividend, 144 | double gamma, double vega, double theta, double undPrice) { 145 | } 146 | 147 | public void deltaNeutralValidation(int reqId, UnderComp underComp) { 148 | } 149 | 150 | public void updateAccountTime(String timeStamp) { 151 | } 152 | 153 | public void updateAccountValue(String key, String value, String currency, 154 | String accountName) { 155 | } 156 | 157 | public void updateMktDepth(int symbolId, int position, int operation, 158 | int side, double price, int size) { 159 | } 160 | 161 | public void updateMktDepthL2(int symbolId, int position, String marketMaker, 162 | int operation, int side, double price, int size) { 163 | } 164 | 165 | public void updateNewsBulletin(int msgId, int msgType, String message, 166 | String origExchange) { 167 | } 168 | 169 | public void updatePortfolio(Contract contract, int position, 170 | double marketPrice, double marketValue, double averageCost, 171 | double unrealizedPNL, double realizedPNL, String accountName) { 172 | } 173 | 174 | public void marketDataType(int reqId, int marketDataType) { 175 | } 176 | 177 | public void tickSnapshotEnd(int tickerId) { 178 | } 179 | 180 | public void connectionClosed() { 181 | } 182 | 183 | public void realtimeBar(int reqId, long time, double open, double high, 184 | double low, double close, long volume, double wap, int count) { 185 | } 186 | 187 | public void tickSize(int orderId, int field, int size) { 188 | } 189 | 190 | public void tickString(int orderId, int tickType, String value) { 191 | } 192 | 193 | public void error(Exception e) { 194 | e.printStackTrace (); 195 | } 196 | 197 | public void error(String str) { 198 | System.err.println (str); 199 | } 200 | 201 | public void error(int id, int errorCode, String errorMsg) { 202 | System.err.println ("error: " + id + "," + errorCode + "," + errorMsg); 203 | } 204 | 205 | public void nextValidId (int orderId) { 206 | } 207 | } -------------------------------------------------------------------------------- /largePriceFeed/WritePriceData.java: -------------------------------------------------------------------------------- 1 | package largePriceFeed; 2 | 3 | import com.ib.client.EClientSocket; 4 | 5 | import java.sql.Connection; 6 | import java.sql.PreparedStatement; 7 | import java.sql.ResultSet; 8 | import java.sql.Statement; 9 | import java.sql.SQLException; 10 | import java.util.Date; 11 | 12 | 13 | public class WritePriceData { 14 | public static final int NULL=0, LOOK=1<<0, LONG=1<<1, SHORT=1<<2, WAIT_FILL=1<<3, WAIT_CANCEL=1<<4; 15 | public int sysState = NULL; 16 | private final RequestPriceData data; 17 | private final EClientSocket socket; 18 | private final Connection sqlConnection; 19 | private Statement statement = null; 20 | private PreparedStatement preparedStatement = null; 21 | private ResultSet resultSet = null; 22 | private double prevLastPrice; 23 | private int bugCounter; 24 | 25 | private static int nextOrderId = 1; 26 | 27 | WritePriceData(RequestPriceData data, EClientSocket socket, 28 | Connection sqlConnection) { 29 | this.data = data; 30 | this.socket = socket; 31 | this.sqlConnection = sqlConnection; 32 | sysState = LOOK; 33 | } 34 | 35 | void check() { 36 | try { 37 | if (data.cont.m_secType.equals("STK")) { 38 | // check that lastPrice isn't a bug 39 | statement = sqlConnection.createStatement(); 40 | resultSet = statement.executeQuery( 41 | "SELECT last FROM IBAlgoSystem.price WHERE symbol='" 42 | + data.cont.m_symbol + "' AND secType='STK';"); 43 | prevLastPrice = outputLastPrice(resultSet); 44 | resultSet = statement.executeQuery( 45 | "SELECT bugCounter FROM IBAlgoSystem.price WHERE symbol='" 46 | + data.cont.m_symbol + "' AND secType='STK';"); 47 | bugCounter = outputBugCounter(resultSet); 48 | 49 | 50 | if ((prevLastPrice > 0.0) && 51 | (Math.abs(data.lastPrice/prevLastPrice - 1) > 0.1) && 52 | (bugCounter < 3)) { 53 | bugCounter++; 54 | preparedStatement = sqlConnection.prepareStatement( 55 | "UPDATE IBAlgoSystem.price SET bugCounter=" 56 | + Integer.toString(bugCounter) + ";"); 57 | } else { 58 | preparedStatement = sqlConnection.prepareStatement( 59 | "UPDATE IBAlgoSystem.price SET bid =" 60 | + Double.toString(data.bidPrice) + ", ask =" 61 | + Double.toString(data.askPrice) + ", last =" 62 | + Double.toString(data.lastPrice) + ", close = " 63 | + Double.toString(data.closePrice) + 64 | ", bugCounter = 0, updateTime = " 65 | + Long.toString((new Date()).getTime()) 66 | + " WHERE symbol = '" + data.cont.m_symbol + 67 | "' AND secType = 'STK' AND currency = '" 68 | + data.cont.m_currency + "';"); 69 | } 70 | 71 | } else if (data.cont.m_secType.equals("OPT")) { 72 | preparedStatement = sqlConnection.prepareStatement( 73 | "UPDATE IBAlgoSystem.price SET bid =" 74 | + Double.toString(data.bidPrice) + ", ask =" + 75 | Double.toString(data.askPrice) + ", last =" 76 | + Double.toString(data.lastPrice) + ", close = " 77 | + Double.toString(data.closePrice) + 78 | ", updateTime = " + Long.toString((new Date()).getTime()) 79 | + " WHERE symbol = '" + data.cont.m_symbol + 80 | "' AND secType = 'OPT' AND currency = '" 81 | + data.cont.m_currency + "' AND expiry = '" 82 | + data.cont.m_expiry + "' AND strike = " + 83 | Double.toString(data.cont.m_strike) + " AND callorput = '" 84 | + data.cont.m_right + "' AND multiplier = '" 85 | + data.cont.m_multiplier + "';"); 86 | 87 | } else if (data.cont.m_secType.equals("CASH")) { 88 | preparedStatement = sqlConnection.prepareStatement( 89 | "UPDATE IBAlgoSystem.price SET bid =" 90 | + Double.toString(data.bidPrice) + ", ask =" + 91 | Double.toString(data.askPrice) + ", last =" 92 | + Double.toString(data.lastPrice) + ", close =" 93 | + Double.toString(data.closePrice) + ", updateTime = " 94 | + Long.toString((new Date()).getTime()) 95 | + " WHERE symbol = '" + data.cont.m_symbol 96 | + "' AND secType = 'CASH' AND currency = '" 97 | + data.cont.m_currency + "';"); 98 | } 99 | preparedStatement.executeUpdate(); 100 | } catch (Exception e) { 101 | e.printStackTrace(); 102 | } 103 | } 104 | 105 | public double outputLastPrice(ResultSet resultSet) throws SQLException { 106 | Double lastPrice = -1.0; 107 | while (resultSet.next()) { 108 | lastPrice = resultSet.getDouble("last"); 109 | } 110 | return lastPrice; 111 | } 112 | 113 | public int outputBugCounter(ResultSet resultSet) throws SQLException { 114 | int bugCounter = 0; 115 | while (resultSet.next()) { 116 | bugCounter = resultSet.getInt("bugCounter"); 117 | } 118 | return bugCounter; 119 | } 120 | } -------------------------------------------------------------------------------- /simplePriceFeed/RequestPriceData.java: -------------------------------------------------------------------------------- 1 | package simplePriceFeed; 2 | 3 | import com.ib.client.Contract; 4 | import com.ib.client.EClientSocket; 5 | 6 | import java.sql.Connection; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | 11 | public class RequestPriceData { 12 | final Contract cont; 13 | private final EClientSocket socket; 14 | private final Connection sqlConnection; 15 | private final WritePriceData writePriceData; 16 | 17 | private static int nextId = 1; 18 | private final int myId; 19 | 20 | List bidPrices = new ArrayList<>(); 21 | List askPrices = new ArrayList<>(); 22 | List lastPrices = new ArrayList<>(); 23 | List closePrices = new ArrayList<>(); 24 | double bidPrice = -1.0; 25 | double askPrice = -1.0; 26 | double lastPrice = -1.0; 27 | double closePrice = -1.0; 28 | 29 | public RequestPriceData(Contract cont, EClientSocket socket, 30 | Connection sqlConnection) { 31 | this.cont = cont; 32 | this.socket = socket; 33 | this.sqlConnection = sqlConnection; 34 | writePriceData = new WritePriceData(this, socket, sqlConnection); 35 | myId = nextId++; 36 | ((RequestPriceWrapper) socket.requestPriceWrapper()).dataMap.put(myId, this); 37 | reqData(); 38 | } 39 | 40 | private void reqData() { 41 | socket.reqMktData(myId, cont, "", false, null); 42 | } 43 | 44 | // record bid price 45 | public void dataRecdBid(double inputPrice) { 46 | bidPrice = inputPrice; 47 | bidPrices.add(inputPrice); 48 | writePriceData.check(); 49 | } 50 | 51 | // record ask price 52 | public void dataRecdAsk(double inputPrice) { 53 | askPrice = inputPrice; 54 | askPrices.add(inputPrice); 55 | writePriceData.check(); 56 | } 57 | 58 | // record last price 59 | public void dataRecdLast(double inputPrice) { 60 | lastPrice = inputPrice; 61 | lastPrices.add(inputPrice); 62 | writePriceData.check(); 63 | } 64 | 65 | // record close price 66 | public void dataRecdClose(double inputPrice) { 67 | closePrice = inputPrice; 68 | closePrices.add(inputPrice); 69 | writePriceData.check(); 70 | } 71 | } -------------------------------------------------------------------------------- /simplePriceFeed/RequestPriceWrapper.java: -------------------------------------------------------------------------------- 1 | package simplePriceFeed; 2 | 3 | import com.ib.client.CommissionReport; 4 | import com.ib.client.Contract; 5 | import com.ib.client.ContractDetails; 6 | import com.ib.client.EWrapper; 7 | import com.ib.client.Execution; 8 | import com.ib.client.Order; 9 | import com.ib.client.OrderState; 10 | import com.ib.client.TickType; 11 | import com.ib.client.UnderComp; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | public class RequestPriceWrapper implements EWrapper{ 17 | public Map dataMap = new HashMap<>(); 18 | 19 | // reqMktData snapshots are received here 20 | public void tickPrice(int tickerId, int field, double price, 21 | int canAutoExecute) { 22 | 23 | // record bid price 24 | if (field == 1) { 25 | dataMap.get(tickerId).dataRecdBid(price); 26 | 27 | // record ask price 28 | } else if (field == 2) { 29 | dataMap.get(tickerId).dataRecdAsk(price); 30 | 31 | // record last price 32 | } else if (field == 4) { 33 | dataMap.get(tickerId).dataRecdLast(price); 34 | 35 | // record close price 36 | } else if (field == 9) { 37 | dataMap.get(tickerId).dataRecdClose(price); 38 | } 39 | } 40 | 41 | public void execDetails(int reqId, Contract contract, Execution execution) { 42 | } 43 | 44 | public void bondContractDetails(int reqId, ContractDetails contractDetails) { 45 | } 46 | 47 | public void contractDetails(int reqId, ContractDetails contractDetails) { 48 | } 49 | 50 | public void contractDetailsEnd(int reqId) { 51 | } 52 | 53 | public void fundamentalData(int reqId, String data) { 54 | } 55 | 56 | public void bondContractDetails(ContractDetails contractDetails) { 57 | } 58 | 59 | public void contractDetails(ContractDetails contractDetails) { 60 | } 61 | 62 | public void currentTime(long time) { 63 | } 64 | 65 | public void displayGroupList(int requestId, String contraftInfo) { 66 | } 67 | 68 | public void displayGroupUpdated(int requestId, String contractInfo) { 69 | } 70 | 71 | public void verifyCompleted(boolean completed, String contractInfo) { 72 | } 73 | 74 | public void verifyMessageAPI(String message) { 75 | } 76 | 77 | public void execDetailsEnd(int reqId) { 78 | } 79 | 80 | public void historicalData(int reqId, String date, double open, double high, 81 | double low, double close, int volume, int count, double WAP, 82 | boolean hasGaps) { 83 | } 84 | 85 | public void managedAccounts(String accountsList) { 86 | } 87 | 88 | public void commissionReport(CommissionReport cr) { 89 | } 90 | 91 | public void position(String account, Contract contract, int pos, 92 | double avgCost) { 93 | } 94 | 95 | public void positionEnd() { 96 | } 97 | 98 | public void accountSummary(int reqId, String account, String tag, 99 | String value, String currency) { 100 | } 101 | 102 | public void accountSummaryEnd(int reqId) { 103 | } 104 | 105 | public void accountDownloadEnd(String accountName) { 106 | } 107 | 108 | public void openOrder(int orderId, Contract contract, Order order, 109 | OrderState orderState) { 110 | } 111 | 112 | public void openOrderEnd() { 113 | } 114 | 115 | public void orderStatus(int orderId, String status, int filled, 116 | int remaining, double avgFillPrice, int permId, int parentId, 117 | double lastFillPrice, int clientId, String whyHeld) { 118 | } 119 | 120 | public void receiveFA (int faDataType, String xml) { 121 | } 122 | 123 | public void scannerData(int reqId, int rank, ContractDetails contractDetails, 124 | String distance, String benchmark, String projection, String legsStr) { 125 | } 126 | 127 | public void scannerDataEnd(int reqId) { 128 | } 129 | 130 | public void scannerParameters(String xml) { 131 | } 132 | 133 | public void tickEFP(int symbolId, int tickType, double basisPoints, 134 | String formattedBasisPoints, double impliedFuture, int holdDays, 135 | String futureExpiry, double dividendImpact, double dividendsToExpiry) { 136 | } 137 | 138 | public void tickGeneric(int symbolId, int tickType, double value) { 139 | } 140 | 141 | public void tickOptionComputation( int tickerId, int field, 142 | double impliedVol, double delta, double optPrice, double pvDividend, 143 | double gamma, double vega, double theta, double undPrice) { 144 | } 145 | 146 | public void deltaNeutralValidation(int reqId, UnderComp underComp) { 147 | } 148 | 149 | public void updateAccountTime(String timeStamp) { 150 | } 151 | 152 | public void updateAccountValue(String key, String value, String currency, 153 | String accountName) { 154 | } 155 | 156 | public void updateMktDepth(int symbolId, int position, int operation, 157 | int side, double price, int size) { 158 | } 159 | 160 | public void updateMktDepthL2(int symbolId, int position, String marketMaker, 161 | int operation, int side, double price, int size) { 162 | } 163 | 164 | public void updateNewsBulletin(int msgId, int msgType, String message, 165 | String origExchange) { 166 | } 167 | 168 | public void updatePortfolio(Contract contract, int position, 169 | double marketPrice, double marketValue, double averageCost, 170 | double unrealizedPNL, double realizedPNL, String accountName) { 171 | } 172 | 173 | public void marketDataType(int reqId, int marketDataType) { 174 | } 175 | 176 | public void tickSnapshotEnd(int tickerId) { 177 | } 178 | 179 | public void connectionClosed() { 180 | } 181 | 182 | public void realtimeBar(int reqId, long time, double open, double high, 183 | double low, double close, long volume, double wap, int count) { 184 | } 185 | 186 | public void tickSize(int orderId, int field, int size) { 187 | } 188 | 189 | public void tickString(int orderId, int tickType, String value) { 190 | } 191 | 192 | public void error(Exception e) { 193 | e.printStackTrace(); 194 | } 195 | 196 | public void error(String str) { 197 | System.err.println(str); 198 | } 199 | 200 | public void error(int id, int errorCode, String errorMsg) { 201 | System.err.println("error: " + id + "," + errorCode + "," + errorMsg); 202 | } 203 | 204 | public void nextValidId (int orderId) { 205 | } 206 | } -------------------------------------------------------------------------------- /simplePriceFeed/WritePriceData.java: -------------------------------------------------------------------------------- 1 | package simplePriceFeed; 2 | 3 | import com.ib.client.EClientSocket; 4 | 5 | import java.sql.Connection; 6 | import java.sql.PreparedStatement; 7 | import java.sql.ResultSet; 8 | import java.sql.Statement; 9 | import java.sql.SQLException; 10 | import java.util.Date; 11 | 12 | 13 | public class WritePriceData { 14 | public static final int NULL=0, LOOK=1<<0, LONG=1<<1, SHORT=1<<2, WAIT_FILL=1<<3, WAIT_CANCEL=1<<4; 15 | public int sysState = NULL; 16 | private final RequestPriceData data; 17 | private final EClientSocket socket; 18 | private final Connection sqlConnection; 19 | private Statement statement = null; 20 | private PreparedStatement preparedStatement = null; 21 | private ResultSet resultSet = null; 22 | private double prevLastPrice; 23 | private int bugCounter; 24 | 25 | private static int nextOrderId = 1; 26 | 27 | WritePriceData(RequestPriceData data, EClientSocket socket, 28 | Connection sqlConnection) { 29 | this.data = data; 30 | this.socket = socket; 31 | this.sqlConnection = sqlConnection; 32 | sysState = LOOK; 33 | } 34 | 35 | void check() { 36 | try { 37 | if (data.cont.m_secType.equals("STK")) { 38 | // check that lastPrice isn't a bug 39 | statement = sqlConnection.createStatement(); 40 | resultSet = statement.executeQuery( 41 | "SELECT last FROM IBAlgoSystem.price WHERE symbol='" 42 | + data.cont.m_symbol + "' AND secType='STK';"); 43 | prevLastPrice = outputLastPrice(resultSet); 44 | resultSet = statement.executeQuery( 45 | "SELECT bugCounter FROM IBAlgoSystem.price WHERE symbol='" 46 | + data.cont.m_symbol + "' AND secType='STK';"); 47 | bugCounter = outputBugCounter(resultSet); 48 | 49 | 50 | if ((prevLastPrice > 0.0) && 51 | (Math.abs(data.lastPrice/prevLastPrice - 1) > 0.1) && 52 | (bugCounter < 3)) { 53 | bugCounter++; 54 | preparedStatement = sqlConnection.prepareStatement( 55 | "UPDATE IBAlgoSystem.price SET bugCounter=" 56 | + Integer.toString(bugCounter) + ";"); 57 | } else { 58 | preparedStatement = sqlConnection.prepareStatement( 59 | "UPDATE IBAlgoSystem.price SET bid =" 60 | + Double.toString(data.bidPrice) + ", ask =" + 61 | Double.toString(data.askPrice) + ", last =" 62 | + Double.toString(data.lastPrice) + ", close =" 63 | + Double.toString(data.closePrice) + 64 | ", bugCounter = 0, updateTime = " 65 | + Long.toString((new Date()).getTime()) 66 | + " WHERE symbol = '" + data.cont.m_symbol + 67 | "' AND secType ='STK' AND currency = '" 68 | + data.cont.m_currency + "';"); 69 | } 70 | 71 | } else if (data.cont.m_secType.equals("OPT")) { 72 | preparedStatement = sqlConnection.prepareStatement( 73 | "UPDATE IBAlgoSystem.price SET bid =" 74 | + Double.toString(data.bidPrice) + ", ask =" + 75 | Double.toString(data.askPrice) + ", last =" 76 | + Double.toString(data.lastPrice) + ", close =" 77 | + Double.toString(data.closePrice) + ", updateTime =" 78 | + Long.toString((new Date()).getTime()) 79 | + " WHERE symbol = '" + data.cont.m_symbol + 80 | "' AND secType = 'OPT' AND currency = '" 81 | + data.cont.m_currency + "' AND expiry='" 82 | + data.cont.m_expiry + "' AND strike =" + 83 | Double.toString(data.cont.m_strike) + " AND callorput = '" 84 | + data.cont.m_right + "' AND multiplier = '" 85 | + data.cont.m_multiplier + "';"); 86 | } 87 | preparedStatement.executeUpdate(); 88 | } catch (Exception e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | 93 | 94 | public double outputLastPrice(ResultSet resultSet) throws SQLException { 95 | Double lastPrice = -1.0; 96 | while (resultSet.next()) { 97 | lastPrice = resultSet.getDouble("last"); 98 | } 99 | return lastPrice; 100 | } 101 | 102 | public int outputBugCounter(ResultSet resultSet) throws SQLException { 103 | int bugCounter = 0; 104 | while (resultSet.next()) { 105 | bugCounter = resultSet.getInt("bugCounter"); 106 | } 107 | return bugCounter; 108 | } 109 | } -------------------------------------------------------------------------------- /tradeStrategy/FetchOrderStatus.java: -------------------------------------------------------------------------------- 1 | package tradeStrategy; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | 8 | 9 | public class FetchOrderStatus { 10 | public int num_fields = 4; 11 | 12 | private final Connection sqlConnection; 13 | private PreparedStatement preparedStatement = null; 14 | private ResultSet resultSet = null; 15 | 16 | 17 | public String[] ReadOrderStatus(int orderID, Connection sqlConnection) { 18 | String[] order_stats = new String[num_fields]; 19 | StringBuilder check_order_stats; 20 | 21 | boolean checks_out = false; 22 | while (!(checks_out)) { 23 | try { 24 | preparedStatement = sqlConnection.prepareStatement( 25 | "SELECT status FROM IBAlgoSystem.orderTracking WHERE orderID = " 26 | + Integer.toString(orderId) + ";"); 27 | resultSet = preparedStatement.executeQuery(); 28 | while (resultSet.next()) { 29 | check_order_stats = new StringBuilder(resultSet.getString( 30 | "status")); 31 | } 32 | 33 | if ((check_order_stats.toString().equals("PendingSubmit")) || 34 | (check_order_stats.toString().equals("PendingCancel")) || 35 | (check_order_stats.toString().equals("PreSubmitted")) || 36 | (check_order_stats.toString().equals("ApiCancelled")) || 37 | (check_order_stats.toString().equals("Cancelled")) || 38 | (check_order_stats.toString().equals("Filled")) || 39 | (check_order_stats.toString().equals("Inactive"))) { 40 | 41 | order_stats[0] = check_order_stats.toString(); 42 | 43 | preparedStatement = sqlConnection.prepareStatement( 44 | "SELECT filled FROM IBAlgoSystem.orderTracking WHERE " 45 | + "orderID = " + Integer.toString(orderId) + ";"); 46 | resultSet = preparedStatement.executeQuery(); 47 | order_stats[1] = Integer.toString(outputSQLInt(resultSet, 48 | "filled")); 49 | 50 | preparedStatement = sqlConnection.prepareStatement( 51 | "SELECT remaining FROM IBAlgoSystem.orderTracking WHERE " 52 | + "orderID = " + Integer.toString(orderId) + ";"); 53 | resultSet = preparedStatement.executeQuery(); 54 | order_stats[2] = Integer.toString(outputSQLInt(resultSet, 55 | "remaining")); 56 | 57 | preparedStatement = sqlConnection.prepareStatement( 58 | "SELECT avgFillPrice FROM IBAlgoSystem.orderTracking " 59 | + "WHERE orderID = " + Integer.toString(orderId) + ";"); 60 | resultSet = preparedStatement.executeQuery(); 61 | order_stats[3] = Double.toString(outputSQLDouble(resultSet, 62 | "avgFillPrice")); 63 | 64 | checks_out = true; 65 | } 66 | } catch (Exception e) { 67 | } 68 | } 69 | return order_stats; 70 | } 71 | 72 | 73 | public void WriteOrderStatus(int orderID, String status, int filled, 74 | int remaining, double avgFillPrice, Connection sqlConnection) { 75 | try { 76 | preparedStatement = sqlConnection.prepareStatement( 77 | "UPDATE IBAlgoSystem.orderTracking SET orderID = " 78 | + Integer.toString(orderID) + ", status = '" + status 79 | + "', filled = " + Integer.toString(filled) + ", remaining = " 80 | + Integer.toString(remaining) + ", avgFillPrice = " 81 | + Double.toString(avgFillPrice) + " WHERE orderID = " 82 | + Integer.toString(orderID) + ";"); 83 | preparedStatement.executeUpdate(); 84 | } catch (Exception e) { 85 | e.printStackTrace(); 86 | } 87 | } 88 | 89 | 90 | public boolean OrderRecorded(int orderID, Connection sqlConnection) { 91 | boolean order_recorded = false; 92 | try { 93 | preparedStatement = sqlConnection.prepareStatement( 94 | "SELECT COUNT(*) FROM IBAlgoSystem.orderTracking WHERE orderID = " 95 | + Integer.toString(orderID) + ";"); 96 | resultSet = preparedStatement.executeQuery(); 97 | while (resultSet.next()) { 98 | if (resultSet.getInt("COUNT(*)") > 0) { 99 | order_recorded = true; 100 | } 101 | } 102 | } catch (Exception e) { 103 | e.printStackTrace(); 104 | } 105 | return order_recorded; 106 | } 107 | 108 | 109 | public int outputSQLInt(ResultSet resultSet, String field_name) throws SQLException { 110 | int output_value = -1; 111 | while (resultSet.next()) { 112 | output_value = resultSet.getInt(field_name); 113 | } 114 | return output_value; 115 | } 116 | 117 | public double outputSQLDouble(ResultSet resultSet, String field_name) throws SQLException { 118 | double output_value = -1.0; 119 | while (resultSet.next()) { 120 | output_value = resultSet.getInt(field_name); 121 | } 122 | return output_value; 123 | } 124 | } -------------------------------------------------------------------------------- /tradeStrategy/TradeStrategyWrapper.java: -------------------------------------------------------------------------------- 1 | package tradeStrategy; 2 | 3 | import tradeStrategy.FetchOrderStatus; 4 | 5 | import com.ib.client.CommissionReport; 6 | import com.ib.client.Contract; 7 | import com.ib.client.ContractDetails; 8 | import com.ib.client.EWrapper; 9 | import com.ib.client.Execution; 10 | import com.ib.client.Order; 11 | import com.ib.client.OrderState; 12 | import com.ib.client.TickType; 13 | import com.ib.client.UnderComp; 14 | 15 | import java.sql.Connection; 16 | import java.sql.PreparedStatement; 17 | 18 | 19 | public class TradeStrategyWrapper implements EWrapper{ 20 | private final Connection sqlConnection; 21 | private PreparedStatement preparedStatement = null; 22 | 23 | public FetchOrderStatus fetchOrderStatus = new FetchOrderStatus(); 24 | 25 | public TradeStrategyWrapper(Connection sqlConnection) { 26 | this.sqlConnection = sqlConnection; 27 | } 28 | 29 | public void bondContractDetails(int reqId, ContractDetails contractDetails) { 30 | } 31 | 32 | public void contractDetails(int reqId, ContractDetails contractDetails) { 33 | } 34 | 35 | public void contractDetailsEnd(int reqId) { 36 | } 37 | 38 | public void fundamentalData(int reqId, String data) { 39 | } 40 | 41 | public void bondContractDetails(ContractDetails contractDetails) { 42 | } 43 | 44 | public void contractDetails(ContractDetails contractDetails) { 45 | } 46 | 47 | public void currentTime(long time) { 48 | } 49 | 50 | public void displayGroupList(int requestId, String contraftInfo) { 51 | } 52 | 53 | public void displayGroupUpdated(int requestId, String contractInfo) { 54 | } 55 | 56 | public void verifyCompleted(boolean completed, String contractInfo) { 57 | } 58 | 59 | public void verifyMessageAPI(String message) { 60 | } 61 | 62 | public void execDetails(int orderId, Contract contract, Execution execution) { 63 | } 64 | 65 | public void execDetailsEnd(int reqId) { 66 | } 67 | 68 | public void historicalData(int reqId, String date, double open, double high, 69 | double low, double close, int volume, int count, double WAP, 70 | boolean hasGaps) { 71 | } 72 | 73 | public void managedAccounts(String accountsList) { 74 | } 75 | 76 | public void commissionReport(CommissionReport cr) { 77 | } 78 | 79 | public void position(String account, Contract contract, int pos, 80 | double avgCost) { 81 | } 82 | 83 | public void positionEnd() { 84 | } 85 | 86 | public void accountSummary(int reqId, String account, String tag, 87 | String value, String currency) { 88 | try { 89 | preparedStatement = sqlConnection.prepareStatement( 90 | "UPDATE IBAlgoSystem.margin SET " + tag + " = " + value + ";"); 91 | preparedStatement.executeUpdate(); 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | } 95 | } 96 | 97 | public void accountSummaryEnd(int reqId) { 98 | } 99 | 100 | public void accountDownloadEnd(String accountName) { 101 | } 102 | 103 | public void openOrder(int orderId, Contract contract, Order order, 104 | OrderState orderState) { 105 | } 106 | 107 | public void openOrderEnd() { 108 | } 109 | 110 | public void orderStatus(int orderId, String status, int filled, 111 | int remaining, double avgFillPrice, int permId, int parentId, 112 | double lastFillPrice, int clientId, String whyHeld) { 113 | fetchOrderStatus.WriteOrderStatus(orderId, status, filled, remaining, 114 | avgFillPrice, sqlConnection); 115 | } 116 | 117 | public void receiveFA (int faDataType, String xml) { 118 | } 119 | 120 | public void scannerData(int reqId, int rank, ContractDetails contractDetails, 121 | String distance, String benchmark, String projection, String legsStr) { 122 | } 123 | 124 | public void scannerDataEnd(int reqId) { 125 | } 126 | 127 | public void scannerParameters(String xml) { 128 | } 129 | 130 | public void tickEFP(int symbolId, int tickType, double basisPoints, 131 | String formattedBasisPoints, double impliedFuture, int holdDays, 132 | String futureExpiry, double dividendImpact, double dividendsToExpiry) { 133 | } 134 | 135 | public void tickGeneric(int symbolId, int tickType, double value) { 136 | } 137 | 138 | public void tickOptionComputation( int tickerId, int field, 139 | double impliedVol, double delta, double optPrice, double pvDividend, 140 | double gamma, double vega, double theta, double undPrice) { 141 | } 142 | 143 | public void deltaNeutralValidation(int reqId, UnderComp underComp) { 144 | } 145 | 146 | public void updateAccountTime(String timeStamp) { 147 | } 148 | 149 | public void updateAccountValue(String key, String value, String currency, 150 | String accountName) { 151 | } 152 | 153 | public void updateMktDepth(int symbolId, int position, int operation, 154 | int side, double price, int size) { 155 | } 156 | 157 | public void updateMktDepthL2(int symbolId, int position, String marketMaker, 158 | int operation, int side, double price, int size) { 159 | } 160 | 161 | public void updateNewsBulletin(int msgId, int msgType, String message, 162 | String origExchange) { 163 | } 164 | 165 | public void updatePortfolio(Contract contract, int position, 166 | double marketPrice, double marketValue, double averageCost, 167 | double unrealizedPNL, double realizedPNL, String accountName) { 168 | } 169 | 170 | public void marketDataType(int reqId, int marketDataType) { 171 | } 172 | 173 | public void tickSnapshotEnd(int tickerId) { 174 | } 175 | 176 | public void connectionClosed() { 177 | } 178 | 179 | public void realtimeBar(int reqId, long time, double open, double high, 180 | double low, double close, long volume, double wap, int count) { 181 | } 182 | 183 | public void tickSize(int orderId, int field, int size) { 184 | } 185 | 186 | public void tickString(int orderId, int tickType, String value) { 187 | } 188 | 189 | public void error(Exception e) { 190 | e.printStackTrace (); 191 | } 192 | 193 | public void error(String str) { 194 | System.err.println (str); 195 | } 196 | 197 | public void error(int id, int errorCode, String errorMsg) { 198 | System.err.println ("error: " + id + "," + errorCode + "," + errorMsg); 199 | } 200 | 201 | public void nextValidId (int orderId) { 202 | } 203 | 204 | public void tickPrice(int orderId, int field, double price, 205 | int canAutoExecute) { 206 | } 207 | } --------------------------------------------------------------------------------