Skip to content

Instantly share code, notes, and snippets.

@Kurry
Created March 4, 2023 20:51
Show Gist options
  • Save Kurry/cc81dc9066ad194694929017c5212dff to your computer and use it in GitHub Desktop.
Save Kurry/cc81dc9066ad194694929017c5212dff to your computer and use it in GitHub Desktop.
package FocusPackage;
import com.assylias.jbloomberg.DataChangeEvent;
import com.assylias.jbloomberg.DefaultBloombergSession;
import com.assylias.jbloomberg.IntradayStudyData;
import com.assylias.jbloomberg.IntradayStudyField;
import com.assylias.jbloomberg.IntradayStudyRequestBuilder;
import com.assylias.jbloomberg.RealtimeField;
import com.assylias.jbloomberg.TypedObject;
import com.bloomberglp.blpapi.CorrelationID;
import com.bloomberglp.blpapi.Element;
import com.bloomberglp.blpapi.Request;
import com.bloomberglp.blpapi.SessionOptions;
import com.bloomberglp.blpapi.Subscription;
import com.bloomberglp.blpapi.SubscriptionList;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.portlandhouse.trading.AlgorithmType;
import com.portlandhouse.trading.LimitPriceCalculator;
import com.portlandhouse.trading.LimitPriceCalculatorBuilder;
import static com.portlandhouse.trading.TargetPriceType.ARRIVAL;
import static com.portlandhouse.trading.TargetPriceType.LAST;
import com.portlandhouse.trading.TradeSideType;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JScrollPane;
import java.util.stream.IntStream;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import static java.util.Map.entry;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.prefs.Preferences;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.border.MatteBorder;
import org.apache.commons.math3.util.Precision;
public class FocusGUI extends WindowAdapter {
public static FocusTrigger Trigger = new FocusTrigger();
public static VWAPTrigger vwapTrigger = new VWAPTrigger();
public static IntradayStudyTrigger intradayStudyTrigger = new IntradayStudyTrigger();
private static final Table<String, String, TypedObject> marketDataTable = HashBasedTable.create();
public static ReferenceRequestTrigger referenceRequestTrigger = new ReferenceRequestTrigger(marketDataTable);
public static SubscriptionRequestTrigger subscriptionRequestTrigger = new SubscriptionRequestTrigger(marketDataTable);
private static final Logger LOGGER = Logger.getLogger("splunkLogger");
public Preferences prefs = Preferences.userNodeForPackage(FocusGUI.class);
final String PREF_HEIGHT = "window_height";
final String PREF_WIDTH = "window_width";
final String PREF_X = "window_position_x";
final String PREF_Y = "window_position_y";
final double SLIPPAGE_BPS = 0.0025;
//time delays for starting the application and signing up for market data
// KLT: This is zero now since there is a latch in the trigger to wait for orders and routes.
final int initialDelayForTickers = 0;
final int secondDelayForFX = 15000;
final int screenRefresh = 1000;
final int studyTimerDelay = 60000;
//formatters
public DecimalFormat curr = new DecimalFormat("$#,###");
public DecimalFormat shares = new DecimalFormat("#,###");
public DecimalFormat perc = new DecimalFormat("#,###0'%'");
public DecimalFormat chg = new DecimalFormat("#,####.##'%'");
//date/time variables
public SimpleDateFormat tradeDateFormat = new SimpleDateFormat("yyyyMMdd");
public static int tradeDate;
public List<Date> holidays = new ArrayList<>();
public Calendar holidayDate[] = new GregorianCalendar[20];
public List<Date> halfDays = new ArrayList<>();
public Calendar halfDayDates[] = new GregorianCalendar[5];
public SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
public SimpleDateFormat today = new SimpleDateFormat("yyyy-MM-dd");
public SimpleDateFormat todayTime = new SimpleDateFormat("HH:mm:ss");
public DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public DecimalFormat px = new DecimalFormat("#,####.##");
public Calendar cal = Calendar.getInstance();
public Calendar prevBizDay = Calendar.getInstance();
public LocalDateTime openTime[] = new LocalDateTime[1000];
public LocalDateTime closeTime[] = new LocalDateTime[1000];
public double sinceOpen[] = new double[1000];
public double fullDay[] = new double[1000];
public double toClose[] = new double[1000];
public String officialOpenTime[] = new String[1000];
public String openTimePlus5[] = new String[1000];
public String openTimePlus10[] = new String[1000];
public String closeCutoff[] = new String[1000];
public String startTechStudies[] = new String[1000];
public String afterOpen45[] = new String[1000];
public String afterOpen60[] = new String[1000];
public String afterOpen90[] = new String[1000];
public String region[] = new String[1000];
private int myTimerDelay;
private Timer myTimer;
private Timer studyTimer;
//GUI components
JFrame frame = new JFrame();
JPanel panel = new JPanel();
public static JLabel Load;
public static JLabel[] Header = new JLabel[1000];
public static JLabel[] Total = new JLabel[1000];
public static JCheckBox[] OverRide = new JCheckBox[1000];
public static JCheckBox Testing;
public static JLabel[] SEQ = new JLabel[1000];
public static JLabel[] Symbol = new JLabel[1000];
public static JLabel[] Side = new JLabel[1000];
public static JLabel[] Type = new JLabel[1000];
public static JLabel[] LimitPx = new JLabel[1000];
public static JLabel[] Idle = new JLabel[1000];
public static JLabel[] Working = new JLabel[1000];
public static JLabel[] Filled = new JLabel[1000];
public static JLabel[] AvgPx = new JLabel[1000];
public static JLabel[] Amount = new JLabel[1000];
public static JLabel[] MarketValue = new JLabel[1000];
public static JLabel[] RemValue = new JLabel[1000];
public static JLabel[] Status = new JLabel[1000];
public static JLabel[] Broker = new JLabel[1000];
public static JLabel[] VwapPx = new JLabel[1000];
public static JLabel[] Strategy = new JLabel[1000];
public static JLabel[] ArrivalBPS = new JLabel[1000];
public static JLabel[] VwapBPS = new JLabel[1000];
public static JLabel[] Volume = new JLabel[1000];
public static JLabel[] ArrivalPrice = new JLabel[1000];
public static JLabel[] PercentFilled = new JLabel[1000];
public static JLabel[] PercentTenDayADV = new JLabel[1000];
public static JLabel[] LastAll = new JLabel[1000];
public static JLabel[] PartRate = new JLabel[1000];
public static JLabel[] LastUpdateAll = new JLabel[1000];
public static JLabel[] VolumeAll = new JLabel[1000];
public static JLabel[] OpenFlag = new JLabel[1000];
public static JLabel[] Algo = new JLabel[1000];
public static JLabel[] Trend = new JLabel[1000];
public static JLabel[] RSI = new JLabel[1000];
public static JLabel[] BollPercent = new JLabel[1000];
public static JLabel[] ThresholdPx = new JLabel[1000];
public static JLabel[] adjPDC = new JLabel[1000];
//public static JLabel[] HSDPercent = new JLabel[1000];
public static JLabel[] VolChg = new JLabel[1000];
public static JLabel[] BASpread = new JLabel[1000];
public static JLabel[] FavVolume = new JLabel[1000];
public static JLabel[] GroupId = new JLabel[1000];
//basket variables
public static ArrayList<OrderTicket> Orders = new ArrayList<>();
public static ArrayList<RouteTicket> Routes = new ArrayList<>();
public static String portfolioName;
public static int basketImbalance;
public static int TradeCount;
public static int RouteCount;
public static int OpenCount;
public static int amountTotal;
public static int idleTotal;
public static int workingTotal;
public static int filledTotal;
public static int a,k,m;
public static int selectAll;
public static double imbalance;
public static double remBuy;
public static double remSell;
public static double totalArrivalBps;
public static double totalVwapBps;
public static double totalMV;
public static double totalArrival$;
public static double totalVwap$;
public static double broadMarketChg;
public static double EUbroadMarketChg;
//order level variables
public static int[] sideSign = new int[1000];
public static String sideLetter;
public static String[] ticker = new String [1000];
public static String[] primaryTicker = new String [1000];
public static String[] groupId = new String[1000];
public static double[] newLimitPx = new double [1000];
public static String[] limitString = new String [1000];
public static int[] marketValue = new int [1000];
public static int[] remValue = new int [1000];
public static double[] bid = new double [1000];
public static double[] ask = new double [1000];
public static double[] last = new double [1000];
public static String[] exchange = new String [1000];
public static String[] currency = new String [1000];
public static String[] currencyTicker = new String [1000];
public static double[] fxRate = new double [1000];
public static String[] algo = new String [1000];
public static double[] priceIndicatedOpen = new double [1000];
public static int[] volIndicatedOpen = new int [1000];
public static double[] lastAll = new double [1000];
public static double[] askAll = new double [1000];
public static double[] bidAll = new double [1000];
public static String[] lastUpdateAll = new String [1000];
public static int[] volumeAll = new int [1000];
public static double[] open = new double [1000];
public static double[] close = new double [1000]; //rename prevClose
public static double[] adjPrevClose = new double [1000];
public static String[] openFlag = new String [1000];
public static String[] openTradeAdjust = new String [1000];
public static String[] imbalanceAdjust = new String [1000];
public static String[] limitAway = new String [1000];
public static int[] childRouteCount = new int [1000];
public static int[] openRouteCount = new int [1000];
public static int[] maxRouteID = new int [1000];
public static double[] avgvolume = new double [1000];
public static double[] mktcap = new double [1000];
public static int[] pxPosMultFactor = new int [1000];
public static double[] bidAskSpread = new double [1000];
public static double[] avgBidAskSpread = new double [1000];
public static double[] vol10 = new double [1000];
public static double[] vol120 = new double [1000];
public static double[] maxVol = new double [1000];
public static double[] adv10 = new double [1000];
public static double[] volChg1d20d = new double [1000];
public static double[] favVolume = new double [1000];
public static double[] favVolumePerc = new double [1000];
public static double[] hsd = new double [1000];
public static double[] arrival = new double [1000];
public static double[] thresholdMove = new double [1000];
public static double[] thresholdPx = new double [1000];
public static double[] rsi = new double [1000];
public static double[] bbPerc = new double [1000];
public static double[] hsdPx = new double [1000];
public static double[] preMktPx = new double [1000];
public static double[] volume = new double [1000];
public static double[] volume20RT = new double [1000];
public static String[] trend = new String [1000];
public static int[] arrival$ = new int [1000];
public static double[] arrivalbps = new double [1000];
public static int[] vwap$ = new int [1000];
public static double[] vwapbps = new double [1000];
public static double[] vwap = new double [1000];
public static double[] projVwap = new double [1000];
public static double[] partRate = new double [1000];
public static String[] pilotGroup = new String [1000];
public static double[] refTickSize = new double [1000];
public static double[] roundFactor = new double [1000];
public static String [] MAtoday = new String [1000];
public static String [] offeringPrelimFilingDate = new String [1000];
public static String[] equitySplitDate = new String [1000];
public static String[] divExDate = new String [1000];
public static double[] divAmount = new double [1000];
//route level variables
public static String [] routeStratType = new String [1000];
public static String [] openStratType = new String [1000];
public static int[] newAmount = new int [1000];
public static String [] algoInput = new String [1000];
public ArrayList<String> d_fields;
//market data variables
public List<String> fxFields = new ArrayList<>();
public static HashSet<String> CurrArray = new HashSet<String>();
private CorrelationID requestFX;
//vwap fields
public Subscription[] mktvwap_sub = new Subscription[1000];
public SubscriptionList mktvwap_subscriptions = new SubscriptionList();
public CorrelationID mktdata_sub_id;
public static boolean[] vwapSent = new boolean[1000];
SimpleDateFormat dateFormat;
public static final Set<String> VALID_STATUSES = Set.of("WORKING", "FILLED", "PARTFILL");
public static final Map<Integer, Boolean> MODIFICATION_MAP = new ConcurrentHashMap<>();
public static final WstiOrderObserver WSTI_ORDER_OBSERVER = new WstiOrderObserver(marketDataTable);
public static final AtomicInteger START_ONCE = new AtomicInteger();
public static final Map<String, String> TICKER_TO_PRIMARY_TICKER = new HashMap<>();
public class SortTickers implements Comparator<OrderTicket> { //puts order_map in alpha
@Override
public int compare(OrderTicket u1, OrderTicket u2) {
return u1.ticker.compareTo(u2.ticker);
}
}
public class SortStatus implements Comparator<OrderTicket> { //sorts order_map by status
@Override
public int compare(OrderTicket u1, OrderTicket u2) {
return u2.status.compareTo(u1.status);
}
}
public class SortGroupId implements Comparator<OrderTicket> { //sorts order_map by status
@Override
public int compare(OrderTicket u1, OrderTicket u2) {
return u1.groupId.compareTo(u2.groupId);
}
}
public FocusGUI() {
super();
int x2 = Integer.parseInt(prefs.get(PREF_X, "600"));
int y2 = Integer.parseInt(prefs.get(PREF_Y, "-800"));
frame.setBounds(x2, y2, 800, 500); //adjust below for final size //(x, y, width, height)
frame.setLayout(new GridBagLayout());
String value = System.getProperty("portfolio", "focus");
if ("focus".equals(value)) {
frame.setTitle("Focus Trader");
} else if ("a_plus".equals(value)) {
frame.setTitle("A+ Trader");
} else if ("pairs".equals(value)) {
frame.setTitle("Pairs Trader");
} else if ("focus_us".equals(value)) {
frame.setTitle("Focus US");
} else if ("ds".equals(value)) {
frame.setTitle("DS Portfolios");
}
frame.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.getContentPane().setBackground(Color.BLACK);
Load = new JLabel(new ImageIcon(getClass().getResource("Loading.gif")));
frame.add(Load);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
//storing preferences for window location when the app is closed
String position = String.valueOf(frame.getLocation());
String x = position.substring(position.indexOf("x=")+2,position.indexOf("y=")-1);
String y = position.substring(position.indexOf("y=")+2,position.indexOf("]"));
Rectangle r = frame.getBounds();
String h = String.valueOf(r.height);
String w = String.valueOf(r.width);
LOGGER.log(Level.FINEST, "Window closed");
prefs.put(PREF_HEIGHT, h);
prefs.put(PREF_WIDTH, w);
prefs.put(PREF_X, x);
prefs.put(PREF_Y, y);
}
});
// //Deadman switch checks "testing" box after 10 minutes of inactivity (no mouse, keyboard action in app)
// Action logout = new AbstractAction() {
// public void actionPerformed(ActionEvent e) {
// //JFrame frame = (JFrame)e.getSource();
// //pop-up box to confirm still active?
// LOGGER.log(Level.FINEST, "Inactive Alert");
// Testing.setSelected(true);
// //frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
// }
// };
// InactivityListener listener = new InactivityListener(frame, logout, 10);
// listener.start();
String username = System.getProperty("user.name");
//LOGGER.log(Level.FINEST, "tradedate is: " + tradeDate);
//portfolioName //"MERGED PORTFOLIO".equals(emsx_notes) //if username is x, then portfolio is y
for (int i=0;i<9;i++){
holidayDate[i] = GregorianCalendar.getInstance();
}
holidayDate[0].set(2019, Calendar.JANUARY, 21);
holidayDate[1].set(2019, Calendar.FEBRUARY, 18);
holidayDate[2].set(2019, Calendar.APRIL, 19);
holidayDate[3].set(2019, Calendar.MAY, 27);
holidayDate[4].set(2019, Calendar.JULY, 4);
holidayDate[5].set(2019, Calendar.SEPTEMBER, 2);
holidayDate[6].set(2019, Calendar.NOVEMBER, 28);
holidayDate[7].set(2019, Calendar.DECEMBER, 25);
holidayDate[8].set(2020, Calendar.JANUARY, 1);
for (int i=0;i<9;i++){
holidays.add(holidayDate[i].getTime());
}
for (int i=0;i<3;i++){
halfDayDates[i] = GregorianCalendar.getInstance();
}
halfDayDates[0].set(2019, Calendar.JULY, 3);
halfDayDates[1].set(2019, Calendar.NOVEMBER, 29);
halfDayDates[2].set(2019, Calendar.DECEMBER, 24);
for (int i=0;i<3;i++){
halfDays.add(halfDayDates[i].getTime());
}
//logic to find prevBizDay here
for (int i=1;i<10;i++){
prevBizDay = Calendar.getInstance();
prevBizDay.add(Calendar.DATE, -i);
int dayOfWeek = prevBizDay.get(Calendar.DAY_OF_WEEK);
if (dayOfWeek != Calendar.SATURDAY && dayOfWeek != Calendar.SUNDAY && !holidays.contains(prevBizDay.getTime())) {
break;
}
}
myTimerDelay = initialDelayForTickers;
myTimer = new Timer(myTimerDelay, screenUpdate);
myTimer.start();
}
public void myInitComponents() {
frame.remove(Load);
LOGGER.log(Level.FINEST, "Remove Loading Screen");
panel.setLayout(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
//panel.setBorder(new MatteBorder(1, 1, 1, 1, Color.GRAY));
GridBagConstraints c = new GridBagConstraints();
GridBagConstraints r = new GridBagConstraints();
GridBagConstraints l = new GridBagConstraints();
r.anchor = GridBagConstraints.EAST;
r.insets = new Insets(1,1,1,1);
l.anchor = GridBagConstraints.WEST;
l.insets = new Insets(1,1,1,1);
c.gridy = 0;
c.insets = new Insets(1,1,1,1);
//add Headers
for (int i=0;i<36;i++){
Header[i] = new JLabel();
Header[i].setBorder(new MatteBorder(0, 0, 1, 1, Color.GRAY));
panel.add(Header[i],c);
Header[i].setForeground(Color.WHITE);
Header[i].setOpaque(true);
Header[i].setBackground(Color.BLACK);
}
Header[0].setText("SEQ");
Header[1].setText("OUT");
Header[2].setText("SIDE");
Header[3].setText("AMOUNT");
Header[4].setText("SYMBOL");
Header[5].setText("TYPE");
Header[6].setText("LIMIT");
Header[7].setText("STAT");
Header[8].setText("BRKR");
Header[9].setText("STRAT");
Header[10].setText("IDLE");
Header[11].setText("WORK");
Header[12].setText("FILLED");
Header[13].setText("REM VALUE");
Header[14].setText("MKT VALUE");
Header[15].setText("% FILLED");
Header[16].setText("%10dADV");
Header[17].setText("AVG PX");
Header[18].setText("ARRIVAL PX");
Header[19].setText("VWAP PX");
Header[20].setText("LAST");
Header[21].setText("VOLUME");
Header[22].setText("UPDATE");
Header[23].setText("ThPx");
Header[24].setText("10%OP");
Header[25].setText("ALGO");
Header[26].setText("A bps");
Header[27].setText("V bps");
Header[28].setText("Part%");
Header[29].setText("Trend");
Header[30].setText("BB%");
Header[31].setText("RSI");
Header[32].setText("Vol Chg");
Header[33].setText("Spread");
Header[34].setText("FavV");
Header[35].setText("GroupId");
c.gridy = 1;
r.gridy = 1;
l.gridy = 1;
for (int i=0;i<36;i++){
Total[i] = new JLabel();
switch (i) {
case 1:
OverRide[TradeCount] = new JCheckBox();
OverRide[TradeCount].setSelected(false);
panel.add(OverRide[TradeCount],c);
break;
case 2:
Testing = new JCheckBox();
Testing.setSelected(false);
panel.add(Testing,c);
break;
//the totals that should be right-aligned
case 3:
case 5:
case 7:
case 10:
case 11:
case 12:
case 14:
case 15:
case 26:
case 27:
panel.add(Total[i],r);
break;
case 4: //left-aligned
panel.add(Total[i],l);
break;
default:
panel.add(Total[i],c);
break;
}
Total[i].setForeground(Color.WHITE);
Total[i].setOpaque(true);
Total[i].setBackground(Color.BLACK);
}
//declare the new JLabels here, with <TradeCount> in place of the [1000] logic?
String value = System.getProperty("portfolio", "focus");
if ("pairs".equals(value)) {
Collections.sort(Orders, new SortGroupId());
} else {
//sort orders alphabetically
Collections.sort(Orders, new SortTickers());
Collections.sort(Orders, new SortStatus());
}
for (int i=0;i<TradeCount;i++){
//center,left,right alignments
c.gridy = i+2;
c.insets = new Insets(2,2,2,2); // (top, left, bottom, right) "padding" //c.gridx = i; c.gridheight = 2; c.gridwidth = 2;
r.gridy = i+2;
r.insets = new Insets(2,2,2,2);
l.gridy = i+2;
l.insets = new Insets(2,2,2,2);
SEQ[i] = new JLabel(String.valueOf(Orders.get(i).sequenceNo));
Symbol[i] = new JLabel(Orders.get(i).ticker);
VwapPx[i] = new JLabel();
Side[i] = new JLabel(Orders.get(i).side);
Type[i] = new JLabel(Orders.get(i).type);
LimitPx[i] = new JLabel(px.format(Orders.get(i).limit_price));
Idle[i] = new JLabel(shares.format(Orders.get(i).idle));
Working[i] = new JLabel(shares.format(Orders.get(i).working));
Filled[i] = new JLabel(shares.format(Orders.get(i).filled));
AvgPx[i] = new JLabel((String.format("%.4f", Orders.get(i).avg_price)));
Amount[i] = new JLabel(shares.format(Orders.get(i).amount));
Status[i] = new JLabel(String.valueOf(Orders.get(i).status));
Broker[i] = new JLabel(String.valueOf(Orders.get(i).broker));
Strategy[i] = new JLabel(String.valueOf(Orders.get(i).strategy));
ArrivalBPS[i] = new JLabel();
VwapBPS[i] = new JLabel();
MarketValue[i] = new JLabel();
RemValue[i] = new JLabel();
ArrivalPrice[i] = new JLabel();
PercentFilled[i] = new JLabel();
LastAll[i] = new JLabel();
LastUpdateAll[i] = new JLabel();
VolumeAll[i] = new JLabel();
OpenFlag[i] = new JLabel();
Algo[i] = new JLabel();
PercentTenDayADV[i] = new JLabel();
PartRate[i] = new JLabel();
ThresholdPx[i] = new JLabel();
RSI[i] = new JLabel();
BollPercent[i] = new JLabel();
Trend[i] = new JLabel();
BASpread[i] = new JLabel();
FavVolume[i] = new JLabel();
GroupId[i] = new JLabel();
VolChg[i] = new JLabel();
OverRide[i] = new JCheckBox();
OverRide[i].setSelected(false);
SEQ[i].setForeground(Color.WHITE);
VwapPx[i].setForeground(Color.WHITE);
Symbol[i].setForeground(Color.WHITE);
MarketValue[i].setForeground(Color.WHITE);
RemValue[i].setForeground(Color.WHITE);
if ("SELL".equals(Orders.get(i).side) || "SHRT".equals(Orders.get(i).side)) {
Symbol[i].setForeground(Color.RED);
Side[i].setForeground(Color.RED);
} else {
Side[i].setForeground(Color.GREEN);
Symbol[i].setForeground(Color.GREEN);
}
Type[i].setForeground(Color.WHITE);
LimitPx[i].setForeground(Color.WHITE);
Idle[i].setForeground(Color.WHITE);
Working[i].setForeground(Color.WHITE);
Filled[i].setForeground(Color.WHITE);
AvgPx[i].setForeground(Color.WHITE);
Amount[i].setForeground(Color.WHITE);
Status[i].setForeground(Color.WHITE);
Broker[i].setForeground(Color.WHITE);
Strategy[i].setForeground(Color.WHITE);
ArrivalPrice[i].setForeground(Color.WHITE);
PercentFilled[i].setForeground(Color.WHITE);
LastAll[i].setForeground(Color.WHITE);
LastUpdateAll[i].setForeground(Color.WHITE);
VolumeAll[i].setForeground(Color.WHITE);
OpenFlag[i].setForeground(Color.WHITE);
PercentTenDayADV[i].setForeground(Color.WHITE);
Algo[i].setForeground(Color.WHITE);
ArrivalBPS[i].setForeground(Color.WHITE);
VwapBPS[i].setForeground(Color.WHITE);
PartRate[i].setForeground(Color.WHITE);
Trend[i].setForeground(Color.WHITE);
RSI[i].setForeground(Color.WHITE);
BollPercent[i].setForeground(Color.WHITE);
ThresholdPx[i].setForeground(Color.WHITE);
BASpread[i].setForeground(Color.WHITE);
FavVolume[i].setForeground(Color.WHITE);
GroupId[i].setForeground(Color.WHITE);
VolChg[i].setForeground(Color.WHITE);
panel.add(SEQ[i], c);
panel.add(OverRide[i], c);
panel.add(Side[i], l);
panel.add(Amount[i], r);
panel.add(Symbol[i], l);
panel.add(Type[i], c);
panel.add(LimitPx[i], r);
panel.add(Status[i], l);
panel.add(Broker[i], l);
panel.add(Strategy[i], l);
panel.add(Idle[i], r);
panel.add(Working[i], r);
panel.add(Filled[i], r);
panel.add(RemValue[i], r);
panel.add(MarketValue[i], r);
panel.add(PercentFilled[i], r);
panel.add(PercentTenDayADV[i], r);
panel.add(AvgPx[i], r);
panel.add(ArrivalPrice[i], r);
panel.add(VwapPx[i], l);
panel.add(LastAll[i], r);
panel.add(VolumeAll[i], r);
panel.add(LastUpdateAll[i], l);
panel.add(ThresholdPx[i], r);
panel.add(OpenFlag[i], c); //24th header
panel.add(Algo[i], l);
panel.add(ArrivalBPS[i], r);
panel.add(VwapBPS[i], r);
panel.add(PartRate[i], r);
panel.add(Trend[i], c);
panel.add(BollPercent[i], r);
panel.add(RSI[i], r);
panel.add(VolChg[i], r);
panel.add(BASpread[i], r);
panel.add(FavVolume[i], r);
panel.add(GroupId[i], r);
}
panel.setBackground(Color.BLACK);
GridBagConstraints b = new GridBagConstraints();
b.gridx=0;
b.gridy=0;
b.gridheight = 10; //b.gridwidth = 10
b.weighty = 1;
b.weightx = 1;
b.fill = GridBagConstraints.BOTH;
b.anchor = GridBagConstraints.NORTHWEST;
frame.add(panel,b);
JScrollPane scrollPanel = new JScrollPane(panel);
frame.getContentPane().add(scrollPanel, b);
b.gridx=0;
b.gridy=11; //b.weighty = 0.5;
b.anchor = GridBagConstraints.NORTHWEST;
int x2 = Integer.parseInt(prefs.get(PREF_X, "600"));
int y2 = Integer.parseInt(prefs.get(PREF_Y, "-800"));
int w2 = Integer.parseInt(prefs.get(PREF_WIDTH, "1525"));
int h2 = Integer.parseInt(prefs.get(PREF_HEIGHT, "700"));
frame.setBounds(x2, y2, w2, h2); //(x, y, width, height) //(600, -800, 800, 500);
panel.setVisible(true);
basketImbalance =0;
OverRide[TradeCount].setSelected(true);
LOGGER.log(Level.FINEST, "Initialize done");
}
public void updateBlotter() throws ParseException {
cal = Calendar.getInstance();
LocalDateTime now = LocalDateTime.now();
IgnoreOpenMomentumIndicator ignoreOpenMomentumIndicator = new IgnoreOpenMomentumIndicator(Orders, adjPrevClose, preMktPx, sideSign);
for (int i=0;i<TradeCount;i++){
if ((Set.of("CHF").contains(currency[i]) || ticker[i].endsWith("SW Equity"))
&& LocalTime.MIN.plusSeconds(Orders.get(i).time_stamp).isBefore(LocalTime.parse(officialOpenTime[i]))) {
Orders.get(i).arrival_price = open[i];
}
if (LocalTime.MIN.plusSeconds(Orders.get(i).time_stamp).isBefore(LocalTime.parse(officialOpenTime[i]))
&& Orders.get(i).arrival_price == 0) {
if ((ticker[i].endsWith("US Equity") || ticker[i].endsWith("CN Equity"))
&& marketDataTable.row(primaryTicker[i]).containsKey(RealtimeField.PX_OFFICIAL_AUCTION_RT.toString())) {
Orders.get(i).arrival_price = marketDataTable.row(primaryTicker[i]).get(RealtimeField.PX_OFFICIAL_AUCTION_RT.toString()).asDouble();
} else {
Orders.get(i).arrival_price = open[i];
}
}
OrderViewModel viewModel = new OrderViewModel(Orders.get(i));
Amount[i].setText(viewModel.getAmount());
Idle[i].setText(viewModel.getIdle());
Working[i].setText(viewModel.getWorking());
Filled[i].setText(viewModel.getFilled());
AvgPx[i].setText(viewModel.getAveragePrice());
Status[i].setText(viewModel.getStatus());
Type[i].setText(viewModel.getType());
LimitPx[i].setText(viewModel.getLimitPrice());
GroupId[i].setText(Orders.get(i).groupId);
MarketDataViewModel marketDataViewModel = new MarketDataViewModel(Orders.get(i).ticker, marketDataTable);
VwapPx[i].setText(String.format("%.4f", vwap[i]));
ArrivalPrice[i].setText(String.format("%.4f", Orders.get(i).arrival_price));
PercentFilled[i].setText(perc.format(((double) Orders.get(i).filled/Orders.get(i).amount) * 100.00));
PercentTenDayADV[i].setText(String.format("%.1f", Orders.get(i).amount/adv10[i] * 100.00));
LastAll[i].setText(String.format("%.2f",lastAll[i]));
VolumeAll[i].setText(String.valueOf(shares.format(volumeAll[i])));
k = 0;
m = 0;
for (int j=0;j<RouteCount;j++){ //only applicable if one order is out at a time?
if (Routes.get(j).sequenceNo == Orders.get(i).sequenceNo && VALID_STATUSES.contains(Routes.get(j).status)) {
RouteViewModel routeViewModel = new RouteViewModel(Routes.get(j));
childRouteCount[i]=++k; //total child orders for the ticker
if (routeViewModel.isLive()){
openRouteCount[i]=++m; //total open routes for the ticker
Strategy[i].setText(routeViewModel.getStrategy());
}
routeStratType[j] = routeViewModel.getRouteStratType();
openStratType[j] = routeViewModel.getOpenStratType();
Broker[i].setText(routeViewModel.getBroker());
Orders.get(i).broker = routeViewModel.getBroker();
}
}
//check if market data is coming in before painting
if (exchange[i] != null){
if (now.isBefore(closeTime[i])) {
sinceOpen[i] = Math.max(0, Duration.between(openTime[i], now).toMinutes());
toClose[i] = Duration.between(now, closeTime[i]).toMinutes() + 1;
} else {
sinceOpen[i] = Duration.between(openTime[i], closeTime[i]).toMinutes();
toClose[i] = 0;
}
if(lastUpdateAll[i] == null || "-".equals(lastUpdateAll[i].substring(4,5))){
//Date update = sdf.parse(lastUpdateAll[i]);
//LastUpdateAll[i].setText(String.valueOf(sdf.format(update)));
lastUpdateAll[i] = today.format(prevBizDay.getTime());
LastUpdateAll[i].setText(today.format(prevBizDay.getTime()));
} else {
Date update = sdf.parse(lastUpdateAll[i]);
LastUpdateAll[i].setText(String.valueOf(sdf.format(update)));
}
if (offeringPrelimFilingDate[i] != null && offeringPrelimFilingDate[i].equals(today.format(cal.getTime())) || offeringPrelimFilingDate[i].equals(today.format(prevBizDay.getTime()))) {
//create new variable to remove from OpenFlag logic below
//don't need to check this with every iteration of update blotter though
}
partRate[i] = (Orders.get(i).filled/volume[i]*100); //Orders.get(i).ticker
PartRate[i].setText(String.format("%.2f", (partRate[i])));
if (partRate[i] > 3) {
PartRate[i].setForeground(Color.YELLOW);
} else {
PartRate[i].setForeground(Color.WHITE);
}
marketValue[i] = (int) ((fxRate[i])*(Orders.get(i).avg_price*Orders.get(i).filled) + (fxRate[i])*last[i]*(Orders.get(i).amount-Orders.get(i).filled)) * pxPosMultFactor[i];
//LOGGER.log(Level.FINEST, "mv Test: " + marketValue[i] + "fx: " + fxRate[i] + "last: " + last[i] + "amt: " + Orders.get(i).amount + "filled: " + Orders.get(i).filled + "mult check: "+ ((fxRate[i])*(Orders.get(i).avg_price*Orders.get(i).filled) + (fxRate[i])*last[i]*(Orders.get(i).amount-Orders.get(i).filled)));
MarketValue[i].setText(String.valueOf(curr.format(marketValue[i])));
//LOGGER.log(Level.FINEST, "FX Test: " + GrLayout.fxRate[i]);
remValue[i] = (int) (fxRate[i]*(Orders.get(i).amount-Orders.get(i).filled)*last[i]) * pxPosMultFactor[i];
RemValue[i].setText(String.valueOf(curr.format(remValue[i])));
//testing
//Type[i].setText(String.valueOf(divAmount[i]));
//graying out remvalues that are limit away
if ("LMT".equals(Orders.get(i).type) && LocalTime.now().isAfter(LocalTime.parse(officialOpenTime[i]))) {
if (TradingUtils.isLimitAway(Orders.get(i).side, Orders.get(i).limit_price, last[i]) && (Orders.get(i).working > 0 || Orders.get(i).idle > 0)) {
RemValue[i].setForeground(Color.GRAY);
MarketValue[i].setForeground(Color.GRAY);
FavVolume[i].setForeground(Color.GRAY);
limitAway[i] = "YES";
} else {
RemValue[i].setForeground(Color.WHITE);
MarketValue[i].setForeground(Color.WHITE);
limitAway[i] = "NO";
FavVolume[i].setForeground(Color.WHITE);
}
}
OrderTicket currentOrder = Orders.get(i);
boolean isLimitAway = "YES".equals(limitAway[i]);
boolean sellOrShort = "SELL".equals(currentOrder.side) || "SHRT".equals(currentOrder.side);
SlippageCalculatorBuilder slippageCalculatorBuilder = new SlippageCalculatorBuilder()
.setFxRate(fxRate[i])
.setIsLimitAway(isLimitAway)
.setSellOrShort(sellOrShort)
.setLast(last[i])
.setOrder(currentOrder);
SlippageCalculator slippageCalculator = slippageCalculatorBuilder.createSlippageCalculator();
if (sellOrShort) {
sideSign[i] = 1;
sideLetter = "S";
} else {
sideSign[i] = -1;
sideLetter = "B";
}
arrival$[i] = slippageCalculator.getArrivalDollars();
arrivalbps[i] = slippageCalculator.getArrivalSlippage();
ArrivalBPS[i].setText((String.format("%.1f", arrivalbps[i] * 10000)));
projVwap[i] = vwap[i] * (sinceOpen[i] / fullDay[i]) + last[i] * slippageCalculator.getVwapMultiplier() * (toClose[i] / fullDay[i]);
vwap$[i] = sinceOpen[i] == 0 ? 0 : slippageCalculator.getVwapDollars(projVwap[i]);
vwapbps[i] = (float) vwap$[i] / (float) marketValue[i];
VwapBPS[i].setText((String.format("%.1f", vwapbps[i] * 10000)));
if (arrivalbps[i] >0) {
ArrivalBPS[i].setForeground(Color.GREEN);
} else {
ArrivalBPS[i].setForeground(Color.RED);
}
if (vwapbps[i] >0) {
VwapBPS[i].setForeground(Color.GREEN);
} else {
VwapBPS[i].setForeground(Color.RED);
}
//close[i] = close[i] - divAmount[i];
adjPrevClose[i] = close[i] - divAmount[i];
thresholdMove[i] = Math.max((maxVol[i]/Math.sqrt(252))/100 + .01,((maxVol[i]/Math.sqrt(252))/100)*1.2);
thresholdPx[i] = adjPrevClose[i]*(1+sideSign[i]*thresholdMove[i]);
if ("US".equals(region[i])) {
if (broadMarketChg>0 && Math.abs(broadMarketChg) > hsd[TradeCount+1] && ("SELL".equals(Orders.get(i).side) || "SHRT".equals(Orders.get(i).side))) {
thresholdMove[i] = Math.max((maxVol[i]/Math.sqrt(252))/100 + .01 + (Math.abs(broadMarketChg) - hsd[TradeCount+1]),((maxVol[i]/Math.sqrt(252))/100 + (Math.abs(broadMarketChg) - hsd[TradeCount+1]))*1.2);
thresholdPx[i] = adjPrevClose[i]*(1+sideSign[i]*thresholdMove[i]);
} else if (broadMarketChg<0 && Math.abs(broadMarketChg) > hsd[TradeCount+1] && ("BUY".equals(Orders.get(i).side) || "COVR".equals(Orders.get(i).side))) {
thresholdMove[i] = Math.max((maxVol[i]/Math.sqrt(252))/100 + .01 + (Math.abs(broadMarketChg) - hsd[TradeCount+1]),((maxVol[i]/Math.sqrt(252))/100 + (Math.abs(broadMarketChg) - hsd[TradeCount+1]))*1.2);
thresholdPx[i] = adjPrevClose[i]*(1+sideSign[i]*thresholdMove[i]);
} else {
thresholdPx[i] = adjPrevClose[i]*(1+sideSign[i]*thresholdMove[i]);
}
}
if ((sideSign[i] == 1 && last[i] > adjPrevClose[i]*(1+hsd[i])) || (sideSign[i] == -1 && last[i] < adjPrevClose[i]*(1-hsd[i])) ){
trend[i] = sideLetter + "F";
} else if ((sideSign[i] == 1 && last[i] < adjPrevClose[i]*(1-hsd[i])) || (sideSign[i] == -1 && last[i] > adjPrevClose[i]*(1+hsd[i])) ){
trend[i] = sideLetter + "U";
} else {
trend[i] = "O";
}
ThresholdPx[i].setText(String.format("%.2f",thresholdPx[i]));
Trend[i].setText(trend[i]);
BollPercent[i].setText(String.format("%.1f",bbPerc[i]*100));
RSI[i].setText(String.format("%.1f",rsi[i]));
if ("FILLED".equals(Orders.get(i).status) || "YES".equals(limitAway[i])){
BollPercent[i].setForeground(Color.GRAY);
RSI[i].setForeground(Color.GRAY);
} else if (sdf.parse(sdf.format(cal.getTime())).after(sdf.parse(afterOpen45[i])) && sdf.parse(sdf.format(cal.getTime())).before(sdf.parse(closeCutoff[i]))){
BollPercent[i].setForeground(Color.WHITE);
RSI[i].setForeground(Color.WHITE);
} else {
BollPercent[i].setForeground(Color.GRAY);
RSI[i].setForeground(Color.GRAY);
}
VolChg[i].setText(perc.format(volChg1d20d[i]));
if (volChg1d20d[i] > 125) {
VolChg[i].setForeground(Color.YELLOW);
} else {
VolChg[i].setForeground(Color.WHITE);
}
bidAskSpread[i] = (ask[i]-bid[i])/last[i]*100;
BASpread[i].setText(String.format("%.2f",bidAskSpread[i])); // + " " + String.format("%.3f",avgBidAskSpread[i]));
if (bidAskSpread[i] > 0.1) {
BASpread[i].setForeground(Color.YELLOW);
} else {
BASpread[i].setForeground(Color.WHITE);
}
Double favorableVolumePercent = favVolume[i]/volumeAll[i]*100;
favVolumePerc[i] = favorableVolumePercent.isNaN() ? 0 : favorableVolumePercent;
FavVolume[i].setText(perc.format(favVolumePerc[i]));
//logic for OPEN FLAG
//liquidity and pre-market check
if (close[i] > 4 && avgvolume[i] >= 100000 && mktcap[i] >= 100000000 && sdf.parse(sdf.format(cal.getTime())).before(sdf.parse(officialOpenTime[i]))) { //add volume theo below somewhere?
//if favorable open indicated
if (priceIndicatedOpen[i] != 0 && ((sideSign[i] == 1 && priceIndicatedOpen[i] > thresholdPx[i]) || (sideSign[i] == -1 && priceIndicatedOpen[i] < thresholdPx[i])) ){
openFlag[i] = "YES";
OpenFlag[i].setText(openFlag[i]);OpenFlag[i].setForeground(Color.BLACK); OpenFlag[i].setOpaque(true); OpenFlag[i].setBackground(Color.YELLOW);
//if nyse and trading pre-market...
} else if (volumeAll[i]>= 500 && !"-".equals(lastUpdateAll[i].substring(4,5)) && "New York".equals(exchange[i]) && sdf.parse(lastUpdateAll[i]).after(sdf.parse("08:59:59")) && sdf.parse(lastUpdateAll[i]).before(sdf.parse("09:29:45"))){
//&& !"-".equals(lastUpdateAll[i].substring(4,5))
//find the appropriate pre-market price to use
if (sideSign[i] == -1) {
preMktPx[i] = Math.max(bidAll[i],Math.min(lastAll[i], askAll[i]));
} else {
preMktPx[i] = Math.min(askAll[i],Math.max(lastAll[i], bidAll[i]));
}
//if move is above/below threshold
if ((sideSign[i] == 1 && preMktPx[i] > thresholdPx[i]) || (sideSign[i] == -1 && preMktPx[i] < thresholdPx[i]) && !ignoreOpenMomentumIndicator.calculate(i)){
openFlag[i] = "YES";
OpenFlag[i].setText(openFlag[i]);OpenFlag[i].setForeground(Color.BLACK); OpenFlag[i].setOpaque(true); OpenFlag[i].setBackground(Color.YELLOW);
} else {
openFlag[i] = "";
OpenFlag[i].setText(openFlag[i]);OpenFlag[i].setForeground(Color.WHITE); OpenFlag[i].setOpaque(false); OpenFlag[i].setBackground(Color.BLACK);
}
//if nasdaq and trading pre-market...
} else if (volumeAll[i]>= 500 && !"-".equals(lastUpdateAll[i].substring(4,5)) && "NASDAQ".equals(exchange[i].substring(0,6)) && sdf.parse(lastUpdateAll[i]).after(sdf.parse("08:59:59")) && sdf.parse(lastUpdateAll[i]).before(sdf.parse("09:27:45"))){
//&& !"-".equals(lastUpdateAll[i].substring(4,5))
//find the appropriate pre-market price to use
if (sideSign[i] == -1) {
preMktPx[i] = Math.max(bidAll[i],Math.min(lastAll[i], askAll[i]));
} else {
preMktPx[i] = Math.min(askAll[i],Math.max(lastAll[i], bidAll[i]));
}
//if move is above/below threshold
if ((sideSign[i] == 1 && preMktPx[i] > thresholdPx[i]) || (sideSign[i] == -1 && preMktPx[i] < thresholdPx[i]) && !ignoreOpenMomentumIndicator.calculate(i)){
openFlag[i] = "YES";
OpenFlag[i].setText(openFlag[i]);OpenFlag[i].setForeground(Color.BLACK); OpenFlag[i].setOpaque(true); OpenFlag[i].setBackground(Color.YELLOW);
} else {
openFlag[i] = "";
OpenFlag[i].setText(openFlag[i]);OpenFlag[i].setForeground(Color.WHITE); OpenFlag[i].setOpaque(false); OpenFlag[i].setBackground(Color.BLACK);
}
} else {
openFlag[i] = "";
OpenFlag[i].setText(openFlag[i]);OpenFlag[i].setForeground(Color.WHITE); OpenFlag[i].setOpaque(false); OpenFlag[i].setBackground(Color.BLACK);
}
}//end of pre open check
} //end lastupdatedate null check
} //end traddecount loop
//updating the aggregated values in row 2
Total[0].setText(String.valueOf(TradeCount));
Total[4].setText("SPY US Equity");
broadMarketChg = (lastAll[TradeCount+1]/close[TradeCount+1]-1);
Total[5].setText(chg.format(broadMarketChg*100));
if (broadMarketChg>0) {
Total[4].setForeground(Color.GREEN);
Total[5].setForeground(Color.GREEN);
} else {
Total[4].setForeground(Color.RED);
Total[5].setForeground(Color.RED);
}
Total[7].setText("SXXPIEX GY");
EUbroadMarketChg = (last[TradeCount+2]/close[TradeCount+2]-1)*100;
Total[8].setText(chg.format(EUbroadMarketChg));
if (EUbroadMarketChg>0) {
Total[7].setForeground(Color.GREEN);
Total[8].setForeground(Color.GREEN);
} else {
Total[7].setForeground(Color.RED);
Total[8].setForeground(Color.RED);
}
remSell = 0; remBuy = 0;
OpenCount = 0;
amountTotal = 0;
idleTotal = 0;
workingTotal = 0;
filledTotal = 0;
for (int i=0;i<TradeCount;i++){
amountTotal += Orders.get(i).amount;
idleTotal += Orders.get(i).idle;
workingTotal += Orders.get(i).working;
filledTotal += Orders.get(i).filled;
if("YES".equals(openFlag[i])){
++OpenCount;
}
if(("SELL".equals(Orders.get(i).side) || "SHRT".equals(Orders.get(i).side)) && (last[i]>Orders.get(i).limit_price || ("MKT".equals(Orders.get(i).type) && Orders.get(i).filled < Orders.get(i).amount))){
remSell += remValue[i];
} else if (("BUY".equals(Orders.get(i).side) || "COVR".equals(Orders.get(i).side)) && (last[i]<Orders.get(i).limit_price || ("MKT".equals(Orders.get(i).type) && Orders.get(i).filled < Orders.get(i).amount))){
remBuy += remValue[i];
}
}
Total[3].setText(shares.format(amountTotal)); //fix
Total[10].setText(shares.format(idleTotal));
Total[11].setText(shares.format(workingTotal));
Total[12].setText(shares.format(filledTotal));
Total[13].setText(curr.format(remBuy+remSell));
if (OpenCount>0){
Total[24].setText(String.valueOf(OpenCount));
Total[24].setForeground(Color.BLACK);Total[24].setOpaque(true);Total[24].setBackground(Color.YELLOW);
} else {
Total[24].setText("");
Total[24].setForeground(Color.WHITE);Total[24].setBackground(Color.BLACK);
}
imbalance = remBuy - remSell;
if (imbalance>0 && basketImbalance==1) {
Total[25].setForeground(Color.GREEN);
} else if (imbalance<0 && basketImbalance==1){
Total[25].setForeground(Color.RED);
} else {
Total[25].setForeground(Color.WHITE);
}
Total[25].setText(curr.format(imbalance)); //curr.format(remSell) + " " + curr.format(remBuy) +
if (IntStream.of(marketValue).sum() > 0) {
totalArrival$ = 0;
totalVwap$ = 0;
totalMV = 0;
for (int i = 0; i < TradeCount; i++) {
if (!TradingUtils.isLimitAway(Orders.get(i).side, Orders.get(i).limit_price, last[i])) {
totalArrival$ += arrival$[i];
totalVwap$ += vwap$[i];
totalMV += marketValue[i];
} else {
double percentFilled = ((double)Orders.get(i).filled/Orders.get(i).amount);
totalArrival$ += arrival$[i] * percentFilled;
totalVwap$ += vwap$[i] * percentFilled;
totalMV += marketValue[i] * percentFilled;
}
}
totalArrivalBps = totalArrival$ / totalMV * 10000;
totalVwapBps = totalVwap$ / totalMV * 10000;
}
Total[14].setText(curr.format(totalMV));
Total[26].setText(String.format("%.1f", totalArrivalBps));
Total[27].setText(String.format("%.1f", totalVwapBps));
if (totalArrivalBps>0) {
Total[26].setForeground(Color.GREEN);
} else {
Total[26].setForeground(Color.RED);
}
if (totalVwapBps>0) {
Total[27].setForeground(Color.GREEN);
} else {
Total[27].setForeground(Color.RED);
}
}
private static final Set<String> LOGS = new HashSet<>();
public void pairsTradeLogic() {
populateOpeningTrades();
checkIfOverrideIsSelected();
// TICKER_TO_PRIMARY_TICKER.entrySet().stream().map((Map.Entry<String, String> entry) -> {
// int openVolume = marketDataTable.row(entry.getValue()).containsKey(Fields.OPENING_VOLUME_AVG) ? marketDataTable.row(entry.getValue()).get(Fields.OPENING_VOLUME_AVG).asInt() : 0;
// System.out.println(entry.getKey() + " " + openVolume);
// List<SubmitOrderRequest> initialOnOpenOrders = openAuctionTransactionManager.getIntialOnOpenOrders(entry.getKey(), openVolume, maxPctOfOpen, competingPercentOfOpen);
// return List.of();
// });
LocalTime referenceTime = LocalTime.now();
ScheduleManager scheduleManager = new ScheduleManager(LocalTime.now());
Map<String, Double> groupIdOrderPct = new HashMap<>();
Map<String, Boolean> groupIdCannotClearOpen = new HashMap<>();
Map<Integer, SubmitOrderRequest> sequenceToOrder = new HashMap<>(sequenceToSubmitOrderRequest); // make a copy
Map<Integer, Integer> chunkSizes = new HashMap<>();
int chunks = 20;
// Rules
// 1. If both can fill open, send all to open.
// 2. If either cannot fill open, sending the proportional amounts to the open.
// 3. Amount remaining after the open should be balanced.
// 4. Handle multi-region
for (int i = 0; i < TradeCount; i++) {
SubmitOrderRequest submitOrderRequest = new SubmitOrderRequest(sequenceToOrder.get(Orders.get(i).sequenceNo));
double amount = Orders.get(i).amount;
double openPctOfOrder = Precision.round(submitOrderRequest.getAmount() / amount, 2);
if (openPctOfOrder < groupIdOrderPct.getOrDefault(Orders.get(i).groupId, Double.MAX_VALUE)) {
groupIdOrderPct.put(Orders.get(i).groupId, openPctOfOrder);
}
}
for (int i = 0; i < TradeCount; i++) {
/* if ("FILLED".equals(Orders.get(i).status) || LocalTime.now().isAfter(closeTime[i].toLocalTime())) {
Algo[i].setForeground(Color.GRAY);
Algo[i].setBackground(Color.BLACK);
Algo[i].setText("OUT");
} else */ if (scheduleManager.isBefore(officialOpenTime[i]) || true) {
if (TradingUtils.shouldBeRoutedToTheOpen(Orders.get(i).status, referenceTime, officialOpenTime[i], Orders.get(i).broker) || true) {
SubmitOrderRequest submitOrderRequest = sequenceToSubmitOrderRequest.get(Orders.get(i).sequenceNo);
openAuctionTransactionManager.updateBrokerPreferences(submitOrderRequest, Orders.get(i).amount, region[i], close[i], roundFactor[i], sideSign[i], 0.45, PortfolioName.FOCUS);
double amount = Orders.get(i).amount;
double openPctOfOrder = Precision.round(submitOrderRequest.getAmount() / amount, 2);
double maxOpenPctOfOrder = groupIdOrderPct.get(Orders.get(i).groupId);
if (openPctOfOrder > maxOpenPctOfOrder) {
submitOrderRequest.setAmount((int)(amount * maxOpenPctOfOrder));
}
if (Testing.isSelected() || OverRide[i].isSelected() && isOverrideSelected(i)) {
if (!LOGS.contains(submitOrderRequest.toString())) {
LOGGER.log(Level.FINEST, submitOrderRequest.toString());
LOGS.add(submitOrderRequest.toString());
}
} else {
transactionManager.addOrder(submitOrderRequest);
Orders.get(i).status = "WORKING";
}
Algo[i].setText(submitOrderRequest.getDescription());
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
}
} else {
}
}
}
private Map<String, List<OrderTicket>> groupByGroupId(List<OrderTicket> orderList) {
Map<String, List<OrderTicket>> groupedObjects = new HashMap<>();
for (OrderTicket objectData : orderList) {
String groupIdentifier = objectData.groupId;
if (!groupedObjects.containsKey(groupIdentifier)) {
groupedObjects.put(groupIdentifier, new ArrayList<>());
}
groupedObjects.get(groupIdentifier).add(objectData);
}
return groupedObjects;
}
public void pairsTradeLogic2() {
Map<String, List<OrderTicket>> groupedOrders = groupByGroupId(Orders);
Map<String, Integer> groupMaxOpenAmounts = new HashMap<>();
Map<String, Double> tickerToCurrencyAdjPx = new HashMap<>();
for (Map.Entry<String, List<OrderTicket>> entry : groupedOrders.entrySet()) {
System.out.println("Group ID: " + entry.getKey());
double groupMaxDollarAmount = Double.MAX_VALUE;
for (OrderTicket objectData : entry.getValue()) {
double maxPctOfOpen = TradingUtils.isFuturesExpiration(LocalDate.now()) ? 0.25 : 0.20;
int openVolume = marketDataTable.row(TICKER_TO_PRIMARY_TICKER.get(objectData.ticker)).get(Fields.OPENING_VOLUME_AVG).asInt();
double currencyAdjPx = marketDataTable.row(objectData.ticker).get("CRNCY_ADJ_PX_LAST").asDouble();
tickerToCurrencyAdjPx.put(objectData.ticker, currencyAdjPx);
int maxOpenVolume = (int) Math.min(objectData.amount, openVolume * maxPctOfOpen);
double maxDollarAmount = maxOpenVolume * currencyAdjPx;
if (maxDollarAmount < groupMaxDollarAmount) {
groupMaxDollarAmount = maxDollarAmount;
}
}
groupMaxOpenAmounts.put(entry.getKey(), (int)groupMaxDollarAmount);
System.out.println();
}
System.out.println(groupMaxOpenAmounts);
for (Map.Entry<String, List<OrderTicket>> entry : groupedOrders.entrySet()) {
System.out.println("Group ID: " + entry.getKey());
int maxAmount = groupMaxOpenAmounts.get(entry.getKey());
List<SubmitOrderRequest> intialOnOpenOrders = openAuctionTransactionManager.getIntialOnOpenOrders(entry.getValue(), tickerToCurrencyAdjPx, maxAmount);
System.out.println(intialOnOpenOrders);
System.out.println();
}
}
private static final ArrayBlockingQueue<SubmitOrderRequest> submitOrderQueue = new ArrayBlockingQueue<>(1000);
private static final Map<Integer, SubmitOrderRequest> sequenceToSubmitOrderRequest = new HashMap<>();
private static final SecurityTransactionManager transactionManager = new SecurityTransactionManager(Orders, Routes);
private static final OpenAuctionTransactionManager openAuctionTransactionManager = new OpenAuctionTransactionManager(Orders, Routes);
private static final List<SubmitOrderRequest> onOpenOrderRequests = new ArrayList<>();
private static final String[] routeType = new String[1000];
public static void populateOpeningTrades() {
double maxPctOfOpen = TradingUtils.isFuturesExpiration(LocalDate.now()) ? 0.25 : 0.20;
if (sequenceToSubmitOrderRequest.isEmpty()) {
TICKER_TO_PRIMARY_TICKER.entrySet().stream().map((Map.Entry<String, String> entry) -> {
double competingPercentOfOpen = WSTI_ORDER_OBSERVER.getCompetingOpenPercent(entry.getValue(), entry.getKey(), TimeFrame.HISTORICAL);
int openVolume = marketDataTable.row(entry.getValue()).containsKey(Fields.OPENING_VOLUME_AVG) ? marketDataTable.row(entry.getValue()).get(Fields.OPENING_VOLUME_AVG).asInt() : 0;
List<SubmitOrderRequest> initialOnOpenOrders = openAuctionTransactionManager.getIntialOnOpenOrders(entry.getKey(), openVolume, maxPctOfOpen, competingPercentOfOpen);
return initialOnOpenOrders;
}).map(initialOnOpenOrders -> {
submitOrderQueue.addAll(initialOnOpenOrders);
return initialOnOpenOrders;
}).forEachOrdered(initialOnOpenOrders -> {
onOpenOrderRequests.addAll(initialOnOpenOrders);
});
for (SubmitOrderRequest submitOrderRequest : onOpenOrderRequests) {
sequenceToSubmitOrderRequest.put(submitOrderRequest.getSequence(), submitOrderRequest);
}
}
}
public void dsTradeLogic() {
checkIfOverrideIsSelected();
LocalTime referenceTime = LocalTime.now();
ScheduleManager scheduleManager = new ScheduleManager(referenceTime);
for (int i = 0; i < TradeCount; i++) {
OrderTicket currentOrder = Orders.get(i);
boolean isLimitAway = "YES".equals(limitAway[i]);
boolean sellOrShort = "SELL".equals(currentOrder.side) || "SHRT".equals(currentOrder.side);
if ("FILLED".equals(Orders.get(i).status) || referenceTime.isAfter(closeTime[i].toLocalTime())) {
Algo[i].setForeground(Color.GRAY);
Algo[i].setBackground(Color.BLACK);
Algo[i].setText("OUT");
} else if (scheduleManager.isBefore(officialOpenTime[i])) {
if (TradingUtils.shouldBeRoutedToTheOpen(Orders.get(i).status, referenceTime, officialOpenTime[i], Orders.get(i).broker)) {
int openVolume = marketDataTable.row(currentOrder.ticker)
.containsKey(Fields.OPENING_VOLUME_AVG) ? marketDataTable.row(TICKER_TO_PRIMARY_TICKER.get(currentOrder.ticker)).get(Fields.OPENING_VOLUME_AVG).asInt() : 0;
int competingNumberOfTrades = OrderSizing.getNumberOfCompetingTrades(currentOrder, Orders);
double povBasedOnCompeting = OrderSizing.getPovBasedOnNumberOfCompetingTrades(competingNumberOfTrades);
int maxAmountSentToOpen = (int) (povBasedOnCompeting * openVolume);
int targetAmount = OrderSizing.getOrderSizeFromMaxAmount(maxAmountSentToOpen, currentOrder.amount);
// TODO: Amount should be correct number of shares for US case
SubmitOrderRequest submitOrderRequest = new SubmitOrderRequest(
currentOrder.sequenceNo,
targetAmount,
OrderType.getEnum(currentOrder.type),
StrategyType.DMA,
currentOrder.ticker,
currentOrder.limit_price,
currentOrder.broker
);
submitOrderRequest.setPov(OrderSizing.getPovBasedOnNumberOfCompetingTrades(competingNumberOfTrades));
int sellOrShortValue = sellOrShort ? 1 : -1;
openAuctionTransactionManager.updateBrokerPreferences(submitOrderRequest, Orders.get(i).amount, region[i], close[i], roundFactor[i], sellOrShortValue, 0.45, PortfolioName.A_PLUS);
if (Testing.isSelected() || OverRide[i].isSelected() && isOverrideSelected(i)) {
if (!LOGS.contains(submitOrderRequest.toString())) {
LOGGER.log(Level.FINEST, submitOrderRequest.toString());
LOGS.add(submitOrderRequest.toString());
}
} else {
transactionManager.addOrder(submitOrderRequest);
Orders.get(i).status = "WORKING";
}
Algo[i].setText(submitOrderRequest.getDescription());
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
}
} else if (isAfterOpen(scheduleManager, i)) {
routeOrderToLSA(i);
} else if (isAfterOpenPlusTen(scheduleManager, i)
|| TradingUtils.isLimitAway(Orders.get(i).side, Orders.get(i).limit_price, last[i])) {
routeOrderToLimit(i);
} else if (scheduleManager.isAfter(closeCutoff[i])) {
routeOrderToVWAP(i);
}
}
}
public void aplusTradeLogic() throws Exception {
populateOpeningTrades();
checkIfOverrideIsSelected();
LocalTime referenceTime = LocalTime.now();
// LocalTime referenceTime = LocalTime.parse("09:00:00");
ScheduleManager scheduleManager = new ScheduleManager(referenceTime);
OrderTracker tracker = new OrderTracker();
for (int i = 0; i < TradeCount; i++) {
tracker.addOrder(Orders.get(i).ticker, Orders.get(i).side, Orders.get(i).status);
}
for (int i = 0; i < TradeCount; i++) {
OrderTicket currentOrder = Orders.get(i);
boolean isLimitAway = "YES".equals(limitAway[i]);
boolean sellOrShort = "SELL".equals(currentOrder.side) || "SHRT".equals(currentOrder.side);
SlippageCalculatorBuilder slippageCalculatorBuilder = new SlippageCalculatorBuilder()
.setFxRate(fxRate[i])
.setIsLimitAway(isLimitAway)
.setSellOrShort(sellOrShort)
.setLast(last[i])
.setOrder(currentOrder);
SlippageCalculator slippageCalculator = slippageCalculatorBuilder.createSlippageCalculator();
// double arrivalSlippage = slippageCalculator.getArrivalSlippage() * 10_000;
if ("FILLED".equals(Orders.get(i).status) || referenceTime.isAfter(closeTime[i].toLocalTime())) {
Algo[i].setForeground(Color.GRAY);
Algo[i].setBackground(Color.BLACK);
Algo[i].setText("OUT");
} else if (scheduleManager.isBefore(officialOpenTime[i])) {
if (TradingUtils.shouldBeRoutedToTheOpen(Orders.get(i).status, referenceTime, officialOpenTime[i], Orders.get(i).broker)) {
SubmitOrderRequest submitOrderRequest = sequenceToSubmitOrderRequest.get(Orders.get(i).sequenceNo);
if (submitOrderRequest != null) {
int sellOrShortValue = sellOrShort ? 1 : -1;
openAuctionTransactionManager.updateBrokerPreferences(submitOrderRequest, Orders.get(i).amount, region[i], close[i], roundFactor[i], sellOrShortValue, 0.45, PortfolioName.A_PLUS);
if (Testing.isSelected() || OverRide[i].isSelected() && isOverrideSelected(i)) {
if (!LOGS.contains(submitOrderRequest.toString())) {
LOGGER.log(Level.FINEST, submitOrderRequest.toString());
LOGS.add(submitOrderRequest.toString());
}
} else {
transactionManager.addOrder(submitOrderRequest);
Orders.get(i).status = "WORKING";
}
Algo[i].setText(submitOrderRequest.getDescription());
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
} else {
Algo[i].setText("WAITING");
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
}
}
} else if (tracker.hasPendingClosingOrder(Orders.get(i).ticker, Orders.get(i).side)) {
LOGGER.log(Level.FINEST, String.format("%s %s is a competing order/waiting to route...", Orders.get(i).ticker, Orders.get(i).side));
Algo[i].setText("WAITING");
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
} else if (isAfterOpen(scheduleManager, i)) {
routeOrderToLSA(i);
} else if (isAfterOpenPlusTen(scheduleManager, i)
|| TradingUtils.isLimitAway(Orders.get(i).side, Orders.get(i).limit_price, last[i])) {
routeOrderToLimit(i);
} else if (scheduleManager.isAfter(closeCutoff[i])) {
routeOrderToVWAP(i);
}
} // end for
}
private void routeOrderToVWAP(int i) {
if ("VWAP".equals(routeType[i]) && newLimitPx[i] == Orders.get(i).limit_price || Testing.isSelected() || isOverrideOnlySelected(i)) {
Algo[i].setText("VWAP " + Orders.get(i).limit_price);
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
} else {
transactionManager.addOrUpdateOrder(
Orders.get(i).sequenceNo,
Orders.get(i).idle,
OrderType.getEnum(Orders.get(i).type),
StrategyType.VWAP,
ticker[i],
Orders.get(i).limit_price,
Orders.get(i).broker
);
routeType[i] = "VWAP";
newLimitPx[i] = Orders.get(i).limit_price;
}
}
private void routeOrderToLimit(int i) {
if (("LSA".equals(routeType[i]) && newLimitPx[i] == Orders.get(i).limit_price) || Testing.isSelected() || isOverrideOnlySelected(i)) {
Algo[i].setText("LSA1 " + Orders.get(i).limit_price);
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
} else {
transactionManager.cancelOrder(Orders.get(i).sequenceNo);
transactionManager.waitTillIdle(Orders.get(i));
transactionManager.addOrUpdateOrder(
Orders.get(i).sequenceNo,
Orders.get(i).idle,
OrderType.getEnum(Orders.get(i).type),
StrategyType.LSA1,
ticker[i],
Orders.get(i).limit_price,
Orders.get(i).broker
);
routeType[i] = "LSA";
newLimitPx[i] = Orders.get(i).limit_price;
}
}
private void routeOrderToLSA(int i) {
LimitPriceCalculator arrivalLimitPriceCalculator = new LimitPriceCalculatorBuilder()
.setPrice(Orders.get(i).arrival_price)
.setLimit(Orders.get(i).limit_price)
.setRoundFactor(roundFactor[i])
.setBps(SLIPPAGE_BPS)
.setSide(TradeSideType.from(Orders.get(i).side))
.setType(ARRIVAL)
.build();
double newLimitPrice = arrivalLimitPriceCalculator.calculate(AlgorithmType.LSA1);
if ("LSA".equals(routeType[i]) && newLimitPx[i] == newLimitPrice || Testing.isSelected() || isOverrideOnlySelected(i)) {
Algo[i].setText("LSA1 " + newLimitPrice);
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
} else {
if (BrokerCode.JEFA.equals(Orders.get(i).broker)) {
transactionManager.cancelOrder(Orders.get(i).sequenceNo);
transactionManager.waitTillIdle(Orders.get(i));
}
transactionManager.addOrUpdateOrder(
Orders.get(i).sequenceNo,
Orders.get(i).idle,
OrderType.getEnum(Orders.get(i).type),
StrategyType.LSA1,
ticker[i],
newLimitPrice,
Orders.get(i).broker
);
routeType[i] = "LSA";
newLimitPx[i] = newLimitPrice;
}
}
private boolean isAfterOpenPlusTen(ScheduleManager scheduleManager, int i) {
return scheduleManager.isAfter(officialOpenTime[i])
&& scheduleManager.isAfter(openTimePlus10[i])
&& scheduleManager.isBefore(closeCutoff[i]);
}
private boolean isAfterOpen(ScheduleManager scheduleManager, int i) {
return scheduleManager.isAfter(officialOpenTime[i]) // TODO: Fix issue where routed one minute before open
&& scheduleManager.isBefore(openTimePlus10[i])
&& Orders.get(i).arrival_price != 0
&& Orders.get(i).filled > 0;
}
public void tradeLogic() throws ParseException, Exception{
cal = Calendar.getInstance();
checkIfOverrideIsSelected();
for (int i=0;i<TradeCount;i++){ //go through each focus security for trade checks
LimitPriceCalculator lastBasedCalculator = new LimitPriceCalculatorBuilder()
.setPrice(last[i])
.setLimit(Orders.get(i).limit_price)
.setRoundFactor(roundFactor[i])
.setBps(SLIPPAGE_BPS)
.setSide(TradeSideType.from(Orders.get(i).side))
.setType(LAST)
.build();
//check if order is override, filled, not ready...
if (isOverrideSelected(i)) {
setOverrideSelected(i);
} else if (Orders.get(i).filled > 0 && Orders.get(i).working == 0 && Orders.get(i).idle > 0 && "YES".equals(openFlag[i])){ //remaining open flag trades
LOGGER.log(Level.FINEST, "Open Idle Trade @" + sdf.format(cal.getTime()));
limitString[i] = "EMSX_LIMIT_PRICE=" + (double) Math.round((Orders.get(i).arrival_price * (1+(sideSign[i]*0.001)))*roundFactor[i])/roundFactor[i];
newLimitPx[i] = (double) Math.round((Orders.get(i).arrival_price * (1+(sideSign[i]*0.001)))*roundFactor[i])/roundFactor[i];
Algo[i].setText("LSA1O " + newLimitPx[i]);
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Orders.get(i).sequenceNo),
"EMSX_AMOUNT=" + String.valueOf(Orders.get(i).idle),
"EMSX_ORDER_TYPE=LMT",
"EMSX_TIF=DAY","EMSX_HAND_INSTRUCTION=ANY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + Orders.get(i).broker,
"ALGO_TYPE=LSA1"};
RouteAlgo routeAlgo = new RouteAlgo();
if (Orders.get(i).idle > Orders.get(i).amount || Testing.isSelected() || ((sideSign[i] == -1 && newLimitPx[i] > Orders.get(i).limit_price) || (sideSign[i] == 1 && newLimitPx[i] < Orders.get(i).limit_price))){
LOGGER.log(Level.FINEST, "REJECT/TESTING");
} else {
routeAlgo.run(algoInput);
}
//when book becomes balanced after an imbalance and multiple routes were cancelled back
} else if (Orders.get(i).filled > 0 && Orders.get(i).working == 0 && Orders.get(i).idle > 0 && (basketImbalance==0)) {
LOGGER.log(Level.FINEST, "Balanced Idle Trade @" + sdf.format(cal.getTime()));
if ("MKT".equals(Orders.get(i).type)) {
limitString[i] = "EMSX_LIMIT_PRICE=-99999";
} else {
limitString[i] = "EMSX_LIMIT_PRICE=" + String.valueOf(Orders.get(i).limit_price);
}
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Orders.get(i).sequenceNo),
"EMSX_AMOUNT=" + String.valueOf(Orders.get(i).idle),
"EMSX_ORDER_TYPE=" + Orders.get(i).type,"EMSX_TIF=DAY","EMSX_HAND_INSTRUCTION=ANY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + Orders.get(i).broker,
"ALGO_TYPE=VWAP"};
RouteAlgo routeAlgo = new RouteAlgo();
if (Orders.get(i).idle > Orders.get(i).amount || Testing.isSelected()){
LOGGER.log(Level.FINEST, "REJECT/TESTING");
} else {
routeAlgo.run(algoInput);
Orders.get(i).idle = 0;
}
} else if (basketImbalance==1 && Orders.get(i).idle > 0 ){ //imbalance idle trades //need to adjust for when it flips to 0
LOGGER.log(Level.FINEST, "Imbalance Idle Trade @" + sdf.format(cal.getTime()));
imbalanceAdjust[i] = "YES";
newLimitPx[i] = lastBasedCalculator.calculate(AlgorithmType.LSA1);
limitString[i] = "EMSX_LIMIT_PRICE=" + String.valueOf(newLimitPx[i]);
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Orders.get(i).sequenceNo),
"EMSX_AMOUNT=" + String.valueOf(Orders.get(i).idle),
"EMSX_ORDER_TYPE=LMT","EMSX_TIF=DAY","EMSX_HAND_INSTRUCTION=ANY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + Orders.get(i).broker,
"ALGO_TYPE=LSA1"};
RouteAlgo routeAlgo = new RouteAlgo();
if (Orders.get(i).idle > Orders.get(i).amount || Testing.isSelected()){
LOGGER.log(Level.FINEST, "REJECT/TESTING");
} else {
routeAlgo.run(algoInput);
Orders.get(i).idle = 0;
}
} else if (("ASSIGN".equals(Orders.get(i).status) || "NEW".equals(Orders.get(i).status)) && sdf.parse(sdf.format(cal.getTime())).after(sdf.parse(officialOpenTime[i])) ){ //orders that got cancelled and are limit away
LOGGER.log(Level.FINEST, "Limit Away Idle Trade @" + sdf.format(cal.getTime()));
if ("MKT".equals(Orders.get(i).type)) {
limitString[i] = "EMSX_LIMIT_PRICE=-99999";
} else {
newLimitPx[i] = Orders.get(i).limit_price;
limitString[i] = "EMSX_LIMIT_PRICE=" + String.valueOf(newLimitPx[i]);
}
Algo[i].setText("VWAPa " + newLimitPx[i]);
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Orders.get(i).sequenceNo),
"EMSX_AMOUNT=" + String.valueOf(Orders.get(i).idle),
"EMSX_ORDER_TYPE=" + Orders.get(i).type,"EMSX_TIF=DAY","EMSX_HAND_INSTRUCTION=ANY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + Orders.get(i).broker,
"ALGO_TYPE=VWAP"};
RouteAlgo routeAlgo = new RouteAlgo();
if (Orders.get(i).idle > Orders.get(i).amount || Testing.isSelected()){
LOGGER.log(Level.FINEST, "REJECT/TESTING");
} else {
routeAlgo.run(algoInput);
}
} else if (isNotRoutedAndShouldBeRouted(i)) {
routeOrderToOpen(i, null, ExecutionModelType.FOCUS);
}
else { //not "OUT" and no idle amount
for (int j = 0; j < RouteCount; j++) {//run through each active route for each approved broker for modify trade logic
if (Routes.get(j).sequenceNo == Orders.get(i).sequenceNo && ("WORKING".equals(Routes.get(j).status) || "PARTFILL".equals(Routes.get(j).status))) {
//openSignal trade
if ("YES".equals(openFlag[i]) && (("NASDAQ".equals(exchange[i].substring(0,6)) && sdf.parse(sdf.format(cal.getTime())).after(sdf.parse("09:27:30")) && sdf.parse(sdf.format(cal.getTime())).before(sdf.parse(officialOpenTime[i])))
|| ("New York".equals(exchange[i]) && sdf.parse(sdf.format(cal.getTime())).after(sdf.parse("09:29:30")) && sdf.parse(sdf.format(cal.getTime())).before(sdf.parse(officialOpenTime[i]))))) {
algo[j] = routeStratType[j];
Algo[i].setText(algo[j] + " OpenFlag");
if (Routes.get(j).amount != (int) Math.ceil(.10* Orders.get(i).amount)) {
LOGGER.log(Level.FINEST, "OpenFlag route trigger: " + Routes.get(j).strategy + " " + Routes.get(j).broker + " " + routeStratType[j] + " @ " + cal.getTime());
openTradeAdjust[i]="YES";
if ("MKT".equals(Orders.get(i).type)) {
limitString[i] = "EMSX_LIMIT_PRICE=-99999";
} else {
limitString[i] = "EMSX_LIMIT_PRICE=" + String.valueOf(Orders.get(i).limit_price);
}
newAmount[j] = (int) Math.ceil(.10* Orders.get(i).amount);
Routes.get(j).amount = (int) Math.ceil(.10* Orders.get(i).amount);
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Routes.get(j).sequenceNo),
"EMSX_ROUTE_ID=" + String.valueOf(Routes.get(j).routeID),
"EMSX_AMOUNT=" + String.valueOf(newAmount[j]),
"EMSX_ORDER_TYPE=" + Orders.get(i).type,"EMSX_TIF=DAY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + Routes.get(j).broker,
"ALGO_TYPE=" + openStratType[j]};
ModifyAlgo modOpen = new ModifyAlgo();
if (Testing.isSelected()){
LOGGER.log(Level.FINEST, "TESTING");
} else {
modOpen.run(algoInput);
}
}
} else if (shouldModifyRoutePreMarket(i, j)) {
// KLT: Since this is real time, we don't need to account for futures expiration.
double competingPercentOfOpen = WSTI_ORDER_OBSERVER.getCompetingOpenPercent(primaryTicker[i], ticker[i], TimeFrame.REALTIME);
double percentOnOpen = Math.max(0.10, 0.20 - competingPercentOfOpen);
AlgorithmRecommendation algorithmRecommendation = AlgorithmRecommendation.from(primaryTicker[i], TimeFrame.REALTIME, Orders.get(i).amount, percentOnOpen, marketDataTable);
if (Math.abs(algorithmRecommendation.getOpen() - Routes.get(j).amount) >= 100) {
if ("MKT".equals(Orders.get(i).type)) {
limitString[i] = "EMSX_LIMIT_PRICE=-99999";
} else {
limitString[i] = "EMSX_LIMIT_PRICE=" + String.valueOf(Orders.get(i).limit_price);
}
newAmount[j] = algorithmRecommendation.getOpen();
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Routes.get(j).sequenceNo),
"EMSX_ROUTE_ID=" + String.valueOf(Routes.get(j).routeID),
"EMSX_AMOUNT=" + String.valueOf(newAmount[j]),
"EMSX_ORDER_TYPE=" + Orders.get(i).type, "EMSX_TIF=DAY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + Routes.get(j).broker,
"ALGO_TYPE=" + AlgorithmType.DMA.toString()};
ModifyAlgo modOpen = new ModifyAlgo();
String timestamp = LocalTime.now().format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM));
String algorithmInputString = Arrays.toString(algoInput);
if (Testing.isSelected()) {
try {
LOGGER.log(Level.FINEST, "TESTING");
String messagePattern = "%s %s TESTING PREMARKET ORDER ROUTED: %s";
LOGGER.log(Level.FINEST, String.format(messagePattern, exchange[i], timestamp, algorithmRecommendation.toString()));
LOGGER.log(Level.FINEST, String.format(messagePattern, exchange[i], timestamp, algorithmInputString));
} catch (Exception ex) {
LOGGER.severe(ex.toString());
}
} else {
LOGGER.log(Level.FINEST, String.format("Competing Open Percent For %s is %.2f", ticker[i], competingPercentOfOpen));
LOGGER.log(Level.FINEST, String.format("Routing %.2f Percent for %s To The Open", percentOnOpen, ticker[i]));
String messagePattern = "%s %s LIVE PREMARKET ORDER MODIFICATION ROUTED: %s";
LOGGER.log(Level.FINEST, String.format(messagePattern, exchange[i], timestamp, algorithmRecommendation.toString()));
LOGGER.log(Level.FINEST, String.format(messagePattern, exchange[i], timestamp, algorithmInputString));
modOpen.run(algoInput);
MODIFICATION_MAP.put(Orders.get(i).sequenceNo, true);
}
}
} else if (sdf.parse(sdf.format(cal.getTime())).after(sdf.parse(closeCutoff[i])) || ("20VWAP".equals(routeStratType[j]) && LocalTime.now().isAfter(openTime[i].toLocalTime().plusMinutes(15)))){
algo[j] = "VWAP";
newLimitPx[j] = Orders.get(i).limit_price;
newAmount[j] = Routes.get(j).amount;
Algo[i].setText("VWAPe " + newLimitPx[j]);
} else if (sdf.parse(sdf.format(cal.getTime())).after(sdf.parse(afterOpen90[i])) && totalArrivalBps > 5 && totalVwapBps > 5 && Orders.get(i).amount/adv10[i] < .04) { //and book is balanced and broad market is good then
newLimitPx[j] = lastBasedCalculator.calculate(AlgorithmType.LSA1);
algo[j] = "LSA1";
newAmount[j] = Routes.get(j).amount;
Algo[i].setText("LSA1t +5s " + newLimitPx[j]);
} else if ((("EU".equals(region[i]) && Math.abs(EUbroadMarketChg) > 1) || ("US".equals(region[i]) && Math.abs(broadMarketChg) > 1) || sdf.parse(sdf.format(cal.getTime())).after(sdf.parse(afterOpen60[i])) || (remSell/remBuy > 2 || remBuy/remSell > 2) ) && remBuy + remSell > 1000000 && (remBuy/remSell >1.1 || remSell/remBuy >1.1) && sdf.parse(sdf.format(cal.getTime())).after(sdf.parse(openTimePlus5[i])) && !WSTI_ORDER_OBSERVER.hasWorkingOrder(ticker[i])) {
//IMBALANCED
basketImbalance = 1;
algo[j] = routeStratType[j];
newAmount[j] = Routes.get(j).amount;
if (algo[j].startsWith("LSA") && TradingUtils.isLimitAway(Orders.get(i).side, Routes.get(j).limit_price, last[i])) {
LimitPriceCalculator calculator = new LimitPriceCalculatorBuilder()
.setPrice(last[i])
.setLimit(Orders.get(i).limit_price)
.setRoundFactor(roundFactor[i])
.setBps(SLIPPAGE_BPS)
.setSide(TradeSideType.from(Orders.get(i).side))
.setType(LAST)
.build();
newLimitPx[j] = calculator.calculate(AlgorithmType.LSA1);
algo[j] = "LSA1";
} else {
newLimitPx[j] = Routes.get(j).limit_price;
}
if (remBuy/remSell >1.1 && !"YES".equals(imbalanceAdjust[i])) { //buy imbalance
if (sideSign[i] == -1) { //reduce buys
newAmount[j] = Routes.get(j).amount - (int) ((Math.min(imbalance,remBuy+remSell-1000000)*(remValue[i]/remBuy))/(last[i]*fxRate[i]));
LOGGER.log(Level.FINEST, ticker[i] + "\t newAmount[j] = " + newAmount[j] + "\t remV[i]=" + remValue[i] + "\t remBuy=" + remBuy);
newLimitPx[j] = lastBasedCalculator.calculate(AlgorithmType.VWAP);
algo[j] = "VWAP";
Algo[i].setText("LSA1t + VWAPr");
} else {
newAmount[j] = Routes.get(j).amount;
newLimitPx[j] = Orders.get(i).limit_price;
algo[j] = "VWAP";
Algo[i].setText("VWAPi " + Orders.get(i).limit_price);
}
} else if (remSell/remBuy >1.1 && !"YES".equals(imbalanceAdjust[i])){ //sell imbalance
if (sideSign[i] == 1) { //reduce sells
newAmount[j] = Routes.get(j).amount - (int) ((Math.min(-1*imbalance,remBuy+remSell-1000000)*(remValue[i]/remSell))/(last[i]*fxRate[i])); //incorporate imbalance over $1mm
LOGGER.log(Level.FINEST, ticker[i] + "\t newAmount[j] = " + newAmount[j] + "\t remV[i]=" + remValue[i] + "\t remSell=" + remSell);
newLimitPx[j] = lastBasedCalculator.calculate(AlgorithmType.VWAP);
algo[j] = "VWAP";
Algo[i].setText("LSA1t + VWAPr");
} else {
newAmount[j] = Routes.get(j).amount;
newLimitPx[j] = Orders.get(i).limit_price;
algo[j] = "VWAP";
Algo[i].setText("VWAPi " + Orders.get(i).limit_price);
}
}
if (newAmount[j] < Routes.get(j).filled) {
newAmount[j] = newAmount[j] + Routes.get(j).filled;
}
//if book becomes balanced again and there are muliple routes live, then cancel them all
// KLT: We want to not cancel the ones that are limit away, because if they are and there route is canceled, is split the VWAP portion again.
} else if (openRouteCount[i]>1 && !TradingUtils.isLimitAway(Orders.get(i).side, Orders.get(i).limit_price, last[i])) {
LOGGER.log(Level.FINEST, "CANCEL MULTI @" + sdf.format(cal.getTime()) + ": " + openRouteCount[i] + " open routes for " + ticker[i]);
Algo[i].setForeground(Color.BLACK);Algo[i].setOpaque(true);Algo[i].setBackground(Color.YELLOW);
basketImbalance = 0;
algo[j] = routeStratType[j];
newAmount[j] = Routes.get(j).amount;
newLimitPx[j] = Routes.get(j).limit_price;
Request request = Trigger.emapisvc.createRequest("CancelRoute");
Element routes = request.getElement("ROUTES");
Element route = routes.appendElement();
route.getElement("EMSX_SEQUENCE").setValue(Orders.get(i).sequenceNo);
route.getElement("EMSX_ROUTE_ID").setValue(Routes.get(j).routeID);
CorrelationID requestID = new CorrelationID("Cancel" + j);
if (Testing.isSelected()){
LOGGER.log(Level.FINEST, "TESTING");
} else {
Trigger.session.sendRequest(request, requestID);
}
} else if (trend[i] != null && sdf.parse(sdf.format(cal.getTime())).after(sdf.parse(afterOpen45[i])) && !WSTI_ORDER_OBSERVER.hasWorkingOrder(ticker[i])) {
//if broad market is ok and book is balanced after 10:15am...
basketImbalance = 0;
imbalanceAdjust[i] = "NO";
newAmount[j] = Routes.get(j).amount;
newLimitPx[j] = lastBasedCalculator.calculate(AlgorithmType.LSA1);
if (!"O".equals(trend[i]) && "F".equals(trend[i].substring(1,2)) && (rsi[i]>80 && bbPerc[i] >.90 || rsi[i]<20 && bbPerc[i] <.10)){
algo[j] = "LSA1";
Algo[i].setText("LSA1t " + newLimitPx[j]);
} else if ("BU".equals(trend[i]) && rsi[i]>30 && bbPerc[i] >.20 && volChg1d20d[i] > 125 && bidAskSpread[i] <=0.1 ){
algo[j] = "LSA2";
Algo[i].setText("LSA2t " + newLimitPx[j]);
} else if ("SU".equals(trend[i]) && rsi[i]<70 && bbPerc[i] <.80 && volChg1d20d[i] > 125 && bidAskSpread[i] <=0.1 ){
algo[j] = "LSA2";
Algo[i].setText("LSA2t " + newLimitPx[j]);
} else if ("O".equals(trend[i]) && favVolumePerc[i] >=25){
LimitPriceCalculator arrivalLimitPriceCalculator = new LimitPriceCalculatorBuilder()
.setPrice(Orders.get(i).arrival_price)
.setLimit(Orders.get(i).limit_price)
.setRoundFactor(roundFactor[i])
.setBps(SLIPPAGE_BPS)
.setSide(TradeSideType.from(Orders.get(i).side))
.setType(ARRIVAL)
.build();
newLimitPx[j] = arrivalLimitPriceCalculator.calculate(AlgorithmType.LSA1);
algo[j] = "LSA1";
Algo[i].setText("LSA1A " + newLimitPx[j]);
} else {
algo[j] = "VWAP";
newLimitPx[j] = Orders.get(i).limit_price;
Algo[i].setText("VWAPb " + Orders.get(i).limit_price);
}
} else {
basketImbalance = 0;
if ("VWAP".equals(routeStratType[j]) || "20VWAP".equals(routeStratType[j])) {
newLimitPx[j] = Orders.get(i).limit_price;
} else {
newLimitPx[j] = Routes.get(j).limit_price;
}
algo[j] = routeStratType[j];
newAmount[j] = Routes.get(j).amount;
Algo[i].setText(algo[j] + "x " + newLimitPx[j]);
}//end algo[j] if statements
//highlight and trade if change is needed
if (("YES".equals(openTradeAdjust[i]) || ("20VWAP".equals(routeStratType[j]) && BrokerCode.JEFA.equals(Routes.get(j).broker))) && Orders.get(i).filled > 0 && Routes.get(j).routeID == 1 || newAmount[j] <= 0){ //cancel openflag amount remaining //replace RouteID logic in case user cancels route first
LOGGER.log(Level.FINEST, "CANCEL OpenFlag Remain @" + sdf.format(cal.getTime()) + " for " + ticker[i]);
Algo[i].setForeground(Color.BLACK);Algo[i].setOpaque(true);Algo[i].setBackground(Color.YELLOW);
Request request = Trigger.emapisvc.createRequest("CancelRoute");
Element routes = request.getElement("ROUTES");
Element route = routes.appendElement();
route.getElement("EMSX_SEQUENCE").setValue(Routes.get(j).sequenceNo);
route.getElement("EMSX_ROUTE_ID").setValue(Routes.get(j).routeID);
LOGGER.log(Level.FINEST, "Request: " + request.toString());
CorrelationID requestID = new CorrelationID("Cancel" + j);
if (Testing.isSelected()){
LOGGER.log(Level.FINEST, "TESTING");
} else {
Trigger.session.sendRequest(request, requestID);
}
} else if (((routeStratType[j].equals(algo[j]) || routeStratType[j].equals(algo[j].substring(0,3))) && ((Routes.get(j).limit_price < newLimitPx[j]*1.001 && Routes.get(j).limit_price > newLimitPx[j]*0.9990) || (newLimitPx[j] == 0 && Routes.get(j).limit_price == 0)) && Routes.get(j).amount == newAmount[j]) || "DMA".equals(routeStratType[j]) || "ZVZZT US Equity".equals(ticker[i])) { //already in set algo, do nothing
//LOGGER.log(Level.FINEST, "OK: " + ticker[i] + "\t algo[j]:" + algo[j] + " = type[j]: " + routeStratType[j] + "\t Amt[j]: " + Routes.get(j).amount + " = newAmt[j]: " + newAmount[j] + "\t Lmt[j]:" + Routes.get(j).limit_price + " ~= newLmt[j]:" + newLimitPx[j]);
if ("LIMIT".equals(Algo[i].getText()) && basketImbalance == 1) {
updateImbalanceAlgoText(i);
}
//LOGGER.log(Level.FINEST, "OK: " + ticker[i] + "\t algo[j]:" + algo[j] + " = type[j]: " + routeStratType[j] + "\t Amt[j]: " + Routes.get(j).amount + " = newAmt[j]: " + newAmount[j] + "\t Lmt[j]:" + Routes.get(j).limit_price + " ~= newLmt[j]:" + newLimitPx[j]);
Algo[i].setForeground(Color.WHITE); Algo[i].setBackground(Color.BLACK); //unhighlight
} else {//strategy or limit need to be modified
LOGGER.log(Level.FINEST, "TRADE @" + sdf.format(cal.getTime()) + " " + ticker[i] + " to " + algo[j]);
Algo[i].setForeground(Color.BLACK);Algo[i].setOpaque(true);Algo[i].setBackground(Color.YELLOW); //highlight
LOGGER.log(Level.FINEST, "algo[j]: " + algo[j] + "\t type[j]: " + routeStratType[j] + "\t Amt[j]: " + Routes.get(j).amount + "\t newAmt[j]: " + newAmount[j] + "\t Lmt[j]: " + Routes.get(j).limit_price + "\t newLmt[j]: " + newLimitPx[j]);
String orderType = OrderTypeStrings.LMT;
if (algo[j].startsWith("LSA") || newLimitPx[j] > 0) {
limitString[i] = "EMSX_LIMIT_PRICE=" + String.valueOf(newLimitPx[j]);
} else {
limitString[i] = "EMSX_LIMIT_PRICE=-99999";
orderType = OrderTypeStrings.MKT;
}
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Orders.get(i).sequenceNo),
"EMSX_ROUTE_ID=" + String.valueOf(Routes.get(j).routeID),
"EMSX_AMOUNT=" + String.valueOf(newAmount[j]),
"EMSX_ORDER_TYPE=" + orderType,"EMSX_TIF=DAY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + Routes.get(j).broker,
"ALGO_TYPE=" + algo[j]};
ModifyAlgo modAlgo = new ModifyAlgo();
if (((sideSign[i] == -1 && newLimitPx[j] > Orders.get(i).limit_price && OrderTypeStrings.LMT.equals(Orders.get(i).type)) || (sideSign[i] == 1 && newLimitPx[j] < Orders.get(i).limit_price && OrderTypeStrings.LMT.equals(Orders.get(i).type))) || (newAmount[j] > Orders.get(i).amount) || Testing.isSelected() || ("YES".equals(limitAway[i]) && "VWAP".equals(routeStratType[i]))){
LOGGER.log(Level.FINEST, "TESTING/LIMIT");
} else {
modAlgo.run(algoInput);
}
}//end i if
}//end j if
}//end of j loop
}//end of trade checks ifs
} //end of tradecount loop
}
public void routeOrderToOpen(int i, AlgorithmType algoType, ExecutionModelType model) throws Exception {
// route new orders
limitString[i] = TradingUtils.limitPrice(Orders.get(i).type, Orders.get(i).limit_price);
double percentOfOpenThreshold = TradingUtils.isFuturesExpiration(LocalDate.now()) ? 0.25 : 0.20;
double competingPercentOfOpen = WSTI_ORDER_OBSERVER.getCompetingOpenPercent(primaryTicker[i], ticker[i], TimeFrame.HISTORICAL);
percentOfOpenThreshold = Math.max(0.10, percentOfOpenThreshold - competingPercentOfOpen);
AlgorithmRecommendation algorithmRecommendation = AlgorithmRecommendation.from(primaryTicker[i], TimeFrame.HISTORICAL, Orders.get(i).idle, percentOfOpenThreshold, marketDataTable);
int quantity = Orders.get(i).idle;
String brokerCode = Orders.get(i).broker;
if (algoType == null && BrokerCode.hasTwentyVWAP(brokerCode, Region.create(region[i]))) {
algoType = AlgorithmType.TWENTY_VWAP;
} else if (algoType == null) {
quantity = algorithmRecommendation.getOpen();
algoType = AlgorithmType.DMA;
}
String orderType = Orders.get(i).type;
// if (BrokerCode.MLAL.equals(Orders.get(i).broker) && OrderTypeStrings.MKT.equals(Orders.get(i).type) && algoType == AlgorithmType.TWENTY_VWAP) {
// limitString[i] = TradingUtils.relativeCloseLimitPrice(close[i], roundFactor[i], sideSign[i], 0.45);
// orderType = OrderTypeStrings.LMT;
// }
int percentOnOpen = (int) Math.ceil(percentOfOpenThreshold * 100);
algoInput = new String[]{"EMSX_SEQUENCE=" + String.valueOf(Orders.get(i).sequenceNo),
"EMSX_AMOUNT=" + String.valueOf(quantity),
"EMSX_ORDER_TYPE=" + orderType,
"EMSX_TIF=DAY",
"EMSX_HAND_INSTRUCTION=ANY",
"EMSX_TICKER=" + ticker[i],
limitString[i],
"EMSX_BROKER=" + brokerCode,
"ALGO_TYPE=" + algoType.toString(),
"EMSX_SIDE=" + Orders.get(i).side,
"REGION=" + region[i],
"PERCENT_ON_OPEN=" + percentOnOpen
};
RouteAlgo routeAlgo = new RouteAlgo();
String timestamp = LocalTime.now().format(DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM));
String algorithmInputString = Arrays.toString(algoInput);
String messagePattern = "%s %s TESTING PREMARKET ORDER ROUTED: %s";
if (algoType == AlgorithmType.TWENTY_VWAP) {
Algo[i].setText("OPEN" + " " + Orders.get(i).limit_price);
} else {
Algo[i].setText(algoType.name() + " " + Orders.get(i).limit_price);
}
Algo[i].setForeground(Color.WHITE);
Algo[i].setBackground(Color.BLACK);
if (!Testing.isSelected()) {
messagePattern = "%s %s LIVE PREMARKET ORDER ROUTED: %s";
Orders.get(i).status = "WORKING";
LOGGER.log(Level.FINEST, String.format("Competing Open Percent For %s is %.2f", ticker[i], competingPercentOfOpen));
LOGGER.log(Level.FINEST, String.format("Routing %d Percent for %s To The Open", percentOnOpen, ticker[i]));
routeAlgo.run(algoInput);
}
if (!LOGS.contains(algorithmInputString)) {
LOGGER.log(Level.FINEST, String.format(messagePattern, exchange[i], timestamp, algorithmRecommendation.toString()));
LOGGER.log(Level.FINEST, String.format(messagePattern, exchange[i], timestamp, algorithmInputString));
LOGS.add(algorithmInputString);
}
}
public boolean isNotRoutedAndShouldBeRouted(int i) {
return TradingUtils.isNotRouted(Orders.get(i).status) &&
LocalTime.now().isBefore(LocalTime.parse(officialOpenTime[i]))
&& marketDataTable.row(primaryTicker[i]).containsKey(Fields.OPENING_VOLUME_AVG) &&
(Orders.get(i).broker != null);
}
public boolean isOverrideOnlySelected(int i) {
return OverRide[i].isSelected();
}
public boolean isOverrideSelected(int i) {
return OverRide[i].isSelected()
|| "FILLED".equals(Orders.get(i).status)
|| "CME".equals(exchange[i])
|| LocalTime.now().isAfter(closeTime[i].toLocalTime())
|| ("YES".equals(limitAway[i]) && Orders.get(i).idle == 0 && LocalTime.now().isBefore(LocalTime.parse(closeCutoff[i])));
}
public void setOverrideSelected(int i) {
Algo[i].setForeground(Color.GRAY);
Algo[i].setBackground(Color.BLACK);
if("YES".equals(limitAway[i]) && Orders.get(i).working > 0){
Algo[i].setText("LIMIT");
} else {
Algo[i].setText("OUT");
}
//checking for idle amounts first (no route[j] logic loops in this part)
}
public void checkIfOverrideIsSelected() {
//check if top override box is checked, that one checks all others
if (OverRide[TradeCount].isSelected()){
for (int i=0;i<TradeCount;i++){
OverRide[i].setSelected(true);
}
selectAll = 1;
} else if(!OverRide[TradeCount].isSelected() && selectAll == 1 ) {
for (int i=0;i<TradeCount;i++){
OverRide[i].setSelected(false);
}
selectAll = 0;
}
}
private void updateImbalanceAlgoText(int i) {
if (remBuy / remSell > 1.1) { //buy imbalance
if (sideSign[i] == -1) { //reduce buys
Algo[i].setText("LSA1t + VWAPr");
} else {
Algo[i].setText("VWAPi " + Orders.get(i).limit_price);
}
} else if (remSell / remBuy > 1.1 ) { //sell imbalance
if (sideSign[i] == 1) { //reduce sells
Algo[i].setText("LSA1t + VWAPr");
} else {
Algo[i].setText("VWAPi " + Orders.get(i).limit_price);
}
}
}
private boolean shouldModifyRoutePreMarket(int i, int j) {
if (algo[j] == null) return false;
if (BrokerCode.hasTwentyVWAP(Orders.get(i).broker, Region.create(region[i]))) return false;
if (!String.valueOf(marketDataTable.row(ticker[i]).get(BloombergFields.ID_MIC_PRIM_EXCH)).equals("XNYS")) return false;
if (MODIFICATION_MAP.containsKey(Orders.get(i).sequenceNo)) return false;
if (Orders.get(i).idle == 0) return false;
return LocalTime.now().isBefore(LocalTime.parse(officialOpenTime[i]))
&& LocalTime.now().isAfter(LocalTime.parse(officialOpenTime[i])
.minusSeconds(15));
}
ActionListener screenUpdate = new ActionListener(){
@Override
public void actionPerformed(ActionEvent theEvent) {
if (myTimerDelay == initialDelayForTickers) {
myInitComponents();
myTimer.stop();
myTimerDelay = secondDelayForFX;
myTimer = new Timer(myTimerDelay, screenUpdate);
myTimer.start();
Trigger.tasvc = Trigger.session.getService(Trigger.service_tasvc);
List<String> securityTickers = new ArrayList<>();
//sign up for market data for EMSX tickers, broad market //assign local variables?
WeakReference<int[]> vwapWeakReference = new WeakReference<>(FocusGUI.volumeAll);
for (int i = 0; i < TradeCount; i++) {
List<String> vwapOverrides = new ArrayList<>();
ticker[i] = Orders.get(i).ticker;
securityTickers.add(Orders.get(i).ticker);
Trigger.mktdata_sub[i] = new Subscription(ticker[i], BloombergConstants.SUBSCRIPTION_FIELDS, new CorrelationID(4 + i)); //need a new correlationID for each ticker
Trigger.mktdata_subscriptions.add(Trigger.mktdata_sub[i]);
final int finalI = i;
vwapOverrides.add("VWAP_START_TIME=" + String.format("%s", LocalTime.MIN.plusSeconds(Orders.get(i).time_stamp)));
subscriptionRequestTrigger.subscribe(ticker[i], Arrays.asList(RealtimeField.RT_VWAP_VOLUME), vwapOverrides, (DataChangeEvent e) -> {
if (e.getDataName().equals("RT_VWAP_VOLUME")) {
vwapWeakReference.get()[finalI] = e.getNewValue().asInt();
}
});
}
List<String> indexFields = Arrays.asList(
"LAST_PRICE",
"PRICE_PREVIOUS_CLOSE_RT"
);
Trigger.mktdata_sub[TradeCount + 1] = new Subscription("SPY US Equity", indexFields, new CorrelationID(4 + TradeCount + 1));
Trigger.mktdata_subscriptions.add(Trigger.mktdata_sub[TradeCount + 1]);
Trigger.mktdata_sub[TradeCount + 2] = new Subscription("SXXPIEX GY Equity", indexFields, new CorrelationID(4 + TradeCount + 2));
Trigger.mktdata_subscriptions.add(Trigger.mktdata_sub[TradeCount + 2]);
securityTickers.add("SPY US Equity");
securityTickers.add("SXXPIEX GY Equity");
try {
Trigger.session.subscribe(Trigger.mktdata_subscriptions);
subscriptionRequestTrigger.subscribe(securityTickers, BloombergConstants.REALTIME_SUBSCRIPTION_FIELDS);
securityTickers.clear();
} catch (IOException ex) {
System.err.println("Failed to create Market Data subscription:" + ex.getMessage());
}
//sign up for ref data for EMSX tickers
Trigger.refdata = Trigger.session.getService(Trigger.service_refdata);
Trigger.request = Trigger.refdata.createRequest("ReferenceDataRequest");
Element securities = Trigger.request.getElement("securities");
for (int i = 0; i < TradeCount; i++) {
securities.appendValue(ticker[i]);
securityTickers.add(ticker[i]);
if ("SW Equity".equals(ticker[i].substring(ticker[i].length() - 9, ticker[i].length()))) {
primaryTicker[i] = ticker[i].replace("SW Equity", "SE Equity");
LOGGER.log(Level.FINEST, primaryTicker[i]);
}
}
securities.appendValue("SPY US Equity");
securities.appendValue("SXXPIEX GY Equity");
Element fieldz = Trigger.request.getElement("fields");
BloombergConstants.REFERENCE_REQUEST_FIELDS.forEach(field -> {
fieldz.appendValue(field);
});
LOGGER.log(Level.FINEST, "Sending Ref Data Request: " + Trigger.request);
Trigger.refdata_req_id = new CorrelationID(3);
try {
referenceRequestTrigger.submit(securityTickers, BloombergConstants.REFERENCE_REQUEST_FIELDS, Map.of("EQY_FUND_CRNCY", "USD"));
Trigger.session.sendRequest(Trigger.request, Trigger.refdata_req_id);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
//sign up for ref tick data for EMSX tickers, using primary tickers for SW names
Trigger.refdata = Trigger.session.getService(Trigger.service_refdata);
Trigger.request = Trigger.refdata.createRequest("ReferenceDataRequest");
Element tickSecurities = Trigger.request.getElement("securities");
for (int i = 0; i < TradeCount; i++) {
if (ticker[i].endsWith("SW Equity")) {
primaryTicker[i] = ticker[i].replace("SW Equity", "SE Equity");
LOGGER.log(Level.FINEST, primaryTicker[i]);
} else {
primaryTicker[i] = ticker[i];
}
tickSecurities.appendValue(primaryTicker[i]);
}
Element flds = Trigger.request.getElement("fields");
flds.appendValue("reference tick size");
LOGGER.log(Level.FINEST, "Sending Ref Tick Data Request: " + Trigger.request);
Trigger.reftick_req_id = new CorrelationID(33333333);
try {
Trigger.session.sendRequest(Trigger.request, Trigger.reftick_req_id);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
} else if (myTimerDelay == secondDelayForFX) { //need the second delay to pick up FX/region/DVD data from initial sub
for (int i = 0; i < TradeCount; i++) {
if ("G3".equals(pilotGroup[i]) || "G2".equals(pilotGroup[i]) || "G1".equals(pilotGroup[i])) {
roundFactor[i] = 20;
} else {
roundFactor[i] = 100;
}
if ("GBp".equals(currency[i])) {
currencyTicker[i] = "GBPUSD Curncy";
CurrArray.add(currencyTicker[i]);
LOGGER.log(Level.FINEST, "Currency Test: " + currency[i]);
} else if (!"USD".equals(currency[i])) {
currencyTicker[i] = currency[i] + "USD Curncy";
LOGGER.log(Level.FINEST, "Currency Test: " + currency[i]);
CurrArray.add(currencyTicker[i]);
} else {
fxRate[i] = 1;
}
if (!"USD".equals(currency[i]) && !"CAD".equals(currency[i])) {
TradingCalendar tradingCalendar;
if ("NOK".equals(currency[i])) {
tradingCalendar = new XoslExchangeCalendar();
} else if ("DKK".equals(currency[i])) {
tradingCalendar = new XcseExchangeCalendar();
} else if ("PLN".equals(currency[i])) {
tradingCalendar = new XwarExchangeCalendar();
} else {
tradingCalendar = new XlonExchangeCalendar();
}
openTime[i] = LocalDateTime.parse(String.valueOf(today.format(cal.getTime())) + " " + tradingCalendar.easternTime(TradingEvent.OPEN), formatter);
closeTime[i] = LocalDateTime.parse(String.valueOf(today.format(cal.getTime())) + " " + tradingCalendar.easternTime(TradingEvent.CLOSE), formatter);
fullDay[i] = (double) Duration.between(openTime[i], closeTime[i]).toMinutes();
officialOpenTime[i] = tradingCalendar.easternTime(TradingEvent.OPEN);
openTimePlus5[i] = tradingCalendar.easternTime(TradingEvent.OPEN_PLUS_FIVE);
openTimePlus10[i] = tradingCalendar.easternTime(TradingEvent.OPEN_PLUS_TEN);
startTechStudies[i] = tradingCalendar.easternTime(TradingEvent.START_TECH_STUDIES);
afterOpen45[i] = tradingCalendar.easternTime(TradingEvent.AFTER_OPEN_FORTY_FIVE);
afterOpen60[i] = tradingCalendar.easternTime(TradingEvent.AFTER_OPEN_SIXTY);
afterOpen90[i] = tradingCalendar.easternTime(TradingEvent.AFTER_OPEN_NINETY);
region[i] = "EU";
marketDataTable.put(ticker[i], "region", TypedObject.of("EU"));
closeCutoff[i] = tradingCalendar.easternTime(TradingEvent.CLOSE_CUTOFF);
roundFactor[i] = TradingUtils.roundFactor(refTickSize[i]);
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.OPEN, openTime[i]));
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.CLOSE_CUTOFF, closeCutoff[i]));
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.CLOSE, closeTime[i]));
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.OPEN_PLUS_FIVE, openTimePlus5[i]));
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.START_TECH_STUDIES, startTechStudies[i]));
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.AFTER_OPEN_FORTY_FIVE, afterOpen45[i]));
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.AFTER_OPEN_SIXTY, afterOpen60[i]));
LOGGER.log(Level.FINEST, String.format("%s %s", TradingEvent.AFTER_OPEN_NINETY, afterOpen90[i]));
} else {
openTime[i] = LocalDateTime.parse(String.valueOf(today.format(cal.getTime())) + " 09:30:00", formatter);
closeTime[i] = LocalDateTime.parse(String.valueOf(today.format(cal.getTime())) + " 16:00:00", formatter);
fullDay[i] = (double) Duration.between(openTime[i], closeTime[i]).toMinutes();
officialOpenTime[i] = "09:30:00";
openTimePlus5[i] = "09:35:00";
openTimePlus10[i] = "09:40:00";
startTechStudies[i] = "10:13:00";
afterOpen45[i] = "10:15:00";
afterOpen60[i] = "10:30:00";
afterOpen90[i] = "11:00:00";
if (halfDays.contains(cal.getTime())) {
closeCutoff[i] = "12:35:00";
} else {
closeCutoff[i] = "15:35:00";
}
region[i] = "US";
marketDataTable.put(ticker[i], "region", TypedObject.of("US"));
String exchangeCode = "";
if (marketDataTable.row(ticker[i]).containsKey(BloombergFields.EQY_PRIM_EXCH_SHRT)) {
exchangeCode = marketDataTable.row(ticker[i]).get(BloombergFields.EQY_PRIM_EXCH_SHRT).asString();
} else if (marketDataTable.row(ticker[i]).containsKey(BloombergFields.EXCH_CODE)) {
exchangeCode = marketDataTable.row(ticker[i]).get(BloombergFields.EXCH_CODE).asString();
}
if (ticker[i].endsWith("US Equity")) {
primaryTicker[i] = ticker[i].replace("US Equity", String.format("%s Equity", exchangeCode));
} else if (ticker[i].endsWith("CN Equity")) {
primaryTicker[i] = ticker[i].replace("CN Equity", String.format("%s Equity", exchangeCode));
} else {
primaryTicker[i] = ticker[i];
}
}
}
try {
List<String> primaryTickers = new ArrayList<>();
for (int i = 0; i < TradeCount; i++) {
TICKER_TO_PRIMARY_TICKER.put(ticker[i], primaryTicker[i]);
marketDataTable.put(ticker[i], "primary", TypedObject.of(primaryTicker[i]));
primaryTickers.add(primaryTicker[i]);
}
LOGGER.log(Level.FINEST, "Primary Tickers: " + primaryTickers);
subscriptionRequestTrigger.subscribe(primaryTickers, Arrays.asList(
RealtimeField.VOLUME_THEO,
RealtimeField.PX_OFFICIAL_AUCTION_RT,
RealtimeField.IN_AUCTION_RT,
RealtimeField.AUCTION_TYPE_REALTIME,
RealtimeField.TIME_AUCTION_CALL_CONCLUSION_RT
));
referenceRequestTrigger.retrieveOpenAuctionVolumes(primaryTickers, 24);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, e.getMessage());
}
myTimer.stop();
myTimerDelay = screenRefresh;
myTimer = new Timer(myTimerDelay, screenUpdate);
myTimer.start();
//timer for technical analysis studies and custom vwap functions
studyTimer = new Timer(studyTimerDelay, studyUpdate);
studyTimer.start();
studyUpdate.actionPerformed(theEvent);
//fx refdata
if (CurrArray.size() > 0) {
Trigger.request = Trigger.refdata.createRequest("ReferenceDataRequest");
Element securities = Trigger.request.getElement("securities");
Element fxFieldz = Trigger.request.getElement("fields");
fxFieldz.appendValue("PX_YEST_CLOSE");
fxFieldz.appendValue("LAST_PRICE"); //needs to be last? make sure if you add new refdata
Trigger.fx_req_id = new CorrelationID(TradeCount + 7);
for (String s : CurrArray) {
securities.appendValue(s);
}
referenceRequestTrigger.submit(CurrArray, Arrays.asList(
"PX_YEST_CLOSE",
"LAST_PRICE"
), Map.of());
LOGGER.log(Level.FINEST, "Sending FX Data Request: " + Trigger.request);
try {
Trigger.session.sendRequest(Trigger.request, Trigger.fx_req_id);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
}
} else { //applies for the screenRefresh timer delay
try {
updateBlotter();
} catch (ParseException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
try {
String value = System.getProperty("portfolio", "focus");
if ("focus".equals(value) || "focus_us".equals(value)) {
tradeLogic();
} else if ("pairs".equals(value)) {
pairsTradeLogic2();
} else if ("a_plus".equals(value)) {
aplusTradeLogic();
} else if ("ds".equals(value)) {
dsTradeLogic();
}
} catch (ParseException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
}
}
};
ActionListener studyUpdate = new ActionListener(){
@Override
public void actionPerformed (ActionEvent theEvent) {
//technical analysis update; needs DST updates for bloomberg's GMT conversion
Calendar local = Calendar.getInstance();
for (int i=0;i<TradeCount;i++){
try {
if (!"FILLED".equals(Orders.get(i).status) && Orders.get(i).arrival_price != 0 && sdf.parse(sdf.format(local.getTime())).after(sdf.parse(startTechStudies[i])) && !vwapSent[i] && sdf.parse(sdf.format(local.getTime())).before(sdf.parse(closeCutoff[i]))){ //vwap sub
LOGGER.log(Level.FINEST, "Mkt VWAP Sub Starting");
List<RealtimeField> vwapFields = Arrays.asList(
RealtimeField.VWAP,
RealtimeField.RT_VWAP_VOLUME,
RealtimeField.MARKET_DEFINED_VWAP_REALTIME,
RealtimeField.RT_MKT_VWAP_VOLUME
);
WeakReference<double[]> vwapWeakReference = new WeakReference<>(FocusGUI.favVolume);
for (int j=0; j<TradeCount; j++) {
List<String> vwapOverrides = new ArrayList<>();
if (!"FILLED".equals(Orders.get(j).status) && FocusGUI.Orders.get(j).arrival_price != 0){
vwapOverrides.add("VWAP_START_TIME=" + String.format("%s", LocalTime.MIN.plusSeconds(Orders.get(j).time_stamp)));
if ("SELL".equals(Orders.get(j).side) || "SHRT".equals(Orders.get(j).side)) {
vwapOverrides.add("VWAP_MIN_PX=" + String.format("%.2f", Math.max(FocusGUI.Orders.get(j).arrival_price, FocusGUI.Orders.get(j).limit_price)));
} else {
vwapOverrides.add("VWAP_MAX_PX=" + String.format("%.2f", Math.min(FocusGUI.Orders.get(j).arrival_price, FocusGUI.Orders.get(j).limit_price > 0 ? FocusGUI.Orders.get(j).limit_price : Double.MAX_VALUE))); //need to clear this field after?
}
final int finalJ = j;
vwapTrigger.subscribe(FocusGUI.ticker[j], vwapFields, vwapOverrides, (DataChangeEvent e) -> {
if (e.getDataName().equals("RT_VWAP_VOLUME")) {
vwapWeakReference.get()[finalJ] = e.getNewValue().asDouble();
}
});
vwapSent[j] = true;
LOGGER.log(Level.FINEST, String.format("Mkt VWAP Sub %s", FocusGUI.ticker[j]));
}
}
}
if (!"FILLED".equals(Orders.get(i).status) && sdf.parse(sdf.format(local.getTime())).after(sdf.parse(startTechStudies[i])) && sdf.parse(sdf.format(local.getTime())).before(sdf.parse(closeCutoff[i])) && !"YES".equals(limitAway[i]) ){ //do not request if already filled or outside limit
IntradayStudyRequestBuilder builder = new IntradayStudyRequestBuilder(ticker[i],
OffsetDateTime.now().minusMinutes(8),
OffsetDateTime.now())
.setChoice("bollStudyAttributes")
.setPeriod(20)
.setLowerBand(2)
.setPriceSourceClose("close")
.setUpperBand(2);
CompletableFuture<IntradayStudyData> future = intradayStudyTrigger.submit(builder);
final int finalI = i;
WeakReference<double[]> weakReference = new WeakReference<>(FocusGUI.bbPerc);
future.thenAccept(studyData -> {
for (OffsetDateTime date : studyData.get().rowKeySet()) {
weakReference.get()[finalI] = studyData.get().row(date).get(IntradayStudyField.BB_PERCENT).asDouble();
}
});
// RSI Study, do not request if order is already filled
IntradayStudyRequestBuilder rsiStudyBuilder = new IntradayStudyRequestBuilder(ticker[i],
OffsetDateTime.now().minusMinutes(8),
OffsetDateTime.now())
.setChoice("rsiStudyAttributes")
.setPeriod(14)
.setPriceSourceClose("close");
WeakReference<double[]> rsiWeakReference = new WeakReference<>(FocusGUI.rsi);
CompletableFuture<IntradayStudyData> rsiFuture = intradayStudyTrigger.submit(rsiStudyBuilder);
rsiFuture.thenAccept(studyData -> {
for (OffsetDateTime date : studyData.get().rowKeySet()) {
rsiWeakReference.get()[finalI] = studyData.get().row(date).get(IntradayStudyField.RSI).asDouble();
}
});
}
} catch (ParseException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
}
}
};
public static void main(String args[]) throws Exception{
Trigger.run();
vwapTrigger.run();
SessionOptions sessionOptions = new SessionOptions();
sessionOptions.setServerPort(8194);
sessionOptions.setServerHost("localhost");
DefaultBloombergSession session = new DefaultBloombergSession(sessionOptions);
session.start();
WstiAggregator aggregator1 = new WstiAggregator(session, WSTI_ORDER_OBSERVER);
aggregator1.run();
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Windows".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
}
java.awt.EventQueue.invokeLater(FocusGUI::new);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment