All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ddfplus.db.Quote Maven / Gradle / Ivy

There is a newer version: 1.1.7
Show newest version
/**
 * Copyright (C) 2004 - 2015 by Barchart.com, Inc. All Rights Reserved.
 * 
 * This software is the proprietary information of Barchart.com, Inc.
 * Use is subject to license terms.
 */

package com.ddfplus.db;

import java.io.Serializable;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import com.ddfplus.enums.MarketConditionType;
import com.ddfplus.messages.DdfMarketBase;
import com.ddfplus.util.DDFDate;
import com.ddfplus.util.ParserHelper;
import com.ddfplus.util.XMLNode;

/**
 * The Quote class encapsulates the complete quotation information for a given
 * Symbol. It contains Session objects which have the data. The Quote object
 * also contains formatting and other information.
 */
public class Quote implements Cloneable, Serializable {

	// By defining the serialVersionUID we can keep Object Serialization
	// consistent.
	private static final long serialVersionUID = 9094149815858170620L;
	
	
	private volatile String _ddfExchange = "";
	private final SymbolInfo _symbolInfo;
	// Prices
	private volatile float _ask = 0.0f;
	private volatile int _askSize = 0;
	private volatile float _bid = 0.0f;
	private volatile int _bidSize = 0;

	// Sessions
	protected volatile Session _combinedSession = new Session(this);
	protected volatile Session _previousSession = new Session(this);
	private final List _sessions = new CopyOnWriteArrayList();

	private volatile char _flag = '\0';
	private volatile MarketConditionType _marketCondition = MarketConditionType.NORMAL;
	protected volatile long _lastUpdated = 0;	
	

	// Original DDF Message
	private volatile DdfMarketBase _message = null;
	private volatile char _permission = '\0';

	public Quote(SymbolInfo symbolInfo) {
		this._symbolInfo = symbolInfo;	
	}

	/**
	 * Clones the Quote object. This creates a copy of the Quote object (as
	 * opposed to just a pointer reference. Useful if you implementing delay
	 * queues, or anything that requires a second physical copy of the Quote.
	 */
	@Override
	public Object clone() {

		Quote q = new Quote(_symbolInfo);

		q._ask = _ask;
		q._askSize = _askSize;
		q._bid = _bid;
		q._bidSize = _bidSize;
		q._ddfExchange = _ddfExchange;
		q._flag = _flag;
		q._lastUpdated = this._lastUpdated;
		q._marketCondition = _marketCondition;

		q._message = _message;
		q._permission = _permission;

		q._combinedSession = (Session) _combinedSession.clone();
		q._previousSession = (Session) _previousSession.clone();

		q._sessions.addAll(_sessions);

		return q;

	}

	/**
	 * Creates a session given a specific day and session code, stores it, and
	 * returns it. Only creates the session if necessary otherwise returns the
	 * current session.
	 * 
	 * @param dayCode
	 *            Day Code
	 * @param sessionCode
	 *            Session Code
	 * 
	 * @return Session Current session object.
	 */
	public Session createSession(char dayCode, char sessionCode) {
		Session session = this.getSession(dayCode, sessionCode);
		if (session == null) {
			session = new Session(this, DDFDate.fromDayCode(dayCode), sessionCode);

			if ((sessionCode == 'R') || (sessionCode == 'T'))
				_sessions.add(session);
		}

		return session;
	}

	/**
	 * Returns the best Ask (offer) price.
	 * 
	 * @return float The Ask price
	 */

	public float getAsk() {
		return _ask;
	}

	/**
	 * Returns the size of the best Ask (Offer).
	 * 
	 * @return int The Ask size
	 */

	public int getAskSize() {
		return _askSize;
	}

	/**
	 * Returns the best bid price.
	 * 
	 * @return The Bid price
	 */
	public float getBid() {
		return _bid;
	}

	/**
	 * Returns the size of the best bid.
	 * 
	 * @return int The bid size
	 */

	public int getBidSize() {
		return _bidSize;
	}

	/**
	 * Returns the change, i.e. the difference between the last price and the
	 * previous day's last (or settling) price.
	 * 
	 * @return float The change
	 */

	public float getChange() {
		float last = this._combinedSession.getLast();
		if (last == 0.0f)
			return 0.0f;

		float prev = _previousSession.getLast();
		if (prev == 0.0f)
			return 0.0f;

		return last - prev;
	}

	/**
	 * Returns the combined trading session for the Quote. The combined session
	 * is the standard session used, and includes both electronic and pit
	 * session, if applicable. For equities, there is only one session.
	 * 
	 * @return Session The combined session object.
	 */

	public Session getCombinedSession() {
		return _combinedSession;
	}

	/**
	 * Returns the ddf exchange code that the Quote is on.
	 * 
	 * @return String - The ddf exchange code.
	 */

	public String getDDFExchange() {
		return _ddfExchange;
	}


	/**
	 * Returns the flag (if any) associated with the quote. Flags could be 'c'
	 * for close, 's' for settle.
	 * 
	 * @return char - the flag
	 */
	public char getFlag() {
		return _flag;
	}

	/**
	 * Last time the Quote was updated in ms.
	 * 
	 * @return update time in ms.
	 */
	public long getLastUpdated() {
		return _lastUpdated;
	}

	/**
	 * Gets the Market Condition for the symbol.
	 * 
	 * @return Market Condition
	 */
	
	public MarketConditionType getMarketCondition() {
		return _marketCondition;
	}
	
	

	/**
	 * Returns the last Message object that influenced this Quote.
	 * 
	 * @return Message The original Message object
	 */

	public DdfMarketBase getMessage() {
		return _message;
	}

	/**
	 * Return the permission of the quote. One of 'R', 'S', 'I'.
	 * 
	 * @return char The mode/permission of the quote.
	 */

	public char getPermission() {
		return _permission;
	}

	/**
	 * Returns the previous trading session for the Quote. The previous session
	 * is used to calculate changes, and to see the data for "yesterday."
	 * 
	 * @return Session The previous session object.
	 */

	public Session getPreviousSession() {
		return _previousSession;
	}

	/**
	 * Returns the specific session for a day and session.
	 * 
	 * @param dayCode
	 *            Day Code
	 * @param sessionCode
	 *            Session Code
	 * 
	 * @return Session
	 */
	
	public Session getSession(char dayCode, char sessionCode) {
		for (Session session : _sessions) {
			if ((session.getDayCode() == dayCode) && (session.getSessionCode() == sessionCode))
				return session;
		}

		return null;
	}

	/**
	 * Returns the symbol of the Quote object, e.g. IBM or ZNZ7
	 * 
	 * @return String The symbol
	 */

	public SymbolInfo getSymbolInfo() {
		return _symbolInfo;
	}

	public void setAsk(float value) {
		_ask = value;
	}

	public void setAskSize(int value) {
		_askSize = value;
	}

	public void setBid(float value) {
		_bid = value;
	}

	public void setBidSize(int value) {
		_bidSize = value;
	}


	/**
	 * Sets the flag.
	 * 
	 * @param value
	 *            char The flag
	 */

	public void setFlag(char value) {
		_flag = value;
	}


	
	public void setCombinedSession(Session session) {
		_combinedSession = session;
	}
	
	
	
	/**
	 * Sets the Market Condition for the symbol.
	 * 
	 * @param value
	 *            char The Market Condition
	 */
	
	public void setMarketCondition(MarketConditionType value) {
		_marketCondition = value;
	}

	/**
	 * Sets the Message object to the quote. This allows the user app to pull
	 * extra data and read deeper into the quote.
	 * 
	 * @param message
	 *            Message The Message object
	 */

	protected void setMessage(DdfMarketBase message) {
		_message = message;
		if (_ddfExchange.length() < 1)
			_ddfExchange = "" + _message.getExchange();
	}


	/**
	 * Sets the ddf exchange code.
	 * 
	 * @param value
	 *            String The ddf exchange
	 */

	public void setDDFExchange(String value) {
		_ddfExchange = value;
	}
	

	public void setPermission(char c) {
		_permission = c;
	}
	
	
	public void setPreviousSession(Session session) {
		_previousSession = session;
	}

	/**
	 * Last Updated in UTC, because this is used by PHP quote systems to compare
	 * against db data, to determine which is fresher.
	 */

	public void updateLastUpdated() {
		_lastUpdated = System.currentTimeMillis();
	}
	
	
	public void updateLastUpdated(long millis) {
		_lastUpdated = millis;
	}
	

	public String toJSONString() {
		Session session = this._combinedSession;
		Session session_t = this.getSession(this._combinedSession.getDayCode(), 'T');

		StringBuilder sb = new StringBuilder("\"" + this._symbolInfo.getSymbol() + "\": { " + "\"symbol\": \""
				+ this._symbolInfo.getSymbol() + "\"" + ", \"name\": \""
				+ this._symbolInfo.getName().replaceAll("\"", "\\\\\"") + "\"" + ", \"exchange\": \""
				+ this._symbolInfo.getExchange() + "\"" + ", \"basecode\": \"" + this._symbolInfo.getBaseCode() + "\""
				+ ", \"pointvalue\": " + this._symbolInfo.getPointValue() + ", \"tickincrement\": "
				+ this._symbolInfo.getTickIncrement() + ", \"ddfexchange\": "
				+ (((this._ddfExchange == null) || (this._ddfExchange.length() == 0)) ? "null"
						: "\"" + this._ddfExchange + "\"")
		);
		
		if (session.getDay() != null) {
			sb.append(
					", \"day\": \"" + session.getDayCode() + "\""
					+ ", \"date\": \"" + LocalDate.from(session.getDay().getDate()).format(DateTimeFormatter.ISO_DATE) + "\""
			);
		}
		
		sb.append(
				", \"flag\": " + ((this._flag != '\0') ? ("\"" + this._flag + "\"") : "null") +
				", \"lastupdate\": " + (new DDFDate(_lastUpdated).toDDFString())
		);

		sb.append(
				", \"bid\": "
						+ ((_bid == ParserHelper.DDFAPI_NOVALUE) ? "null"
								: ParserHelper.float2string(_bid, this._symbolInfo.getBaseCode(),
										ParserHelper.PURE_DECIMAL))
						+ ", \"bidsize\": " + ((_bidSize == ParserHelper.DDFAPI_NOVALUE) ? "null" : _bidSize * 100)
						+ ", \"ask\": "
						+ ((_ask == ParserHelper.DDFAPI_NOVALUE) ? "null"
								: ParserHelper.float2string(_ask, this._symbolInfo.getBaseCode(),
										ParserHelper.PURE_DECIMAL))
						+ ", \"asksize\": " + ((_askSize == ParserHelper.DDFAPI_NOVALUE) ? "null" : _askSize * 100));


		sb.append(", " + "\"open\": "
				+ ((session.getOpen() == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getOpen(), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"high\": "
				+ ((session.getHigh() == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getHigh(), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"low\": "
				+ ((session.getLow() == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getLow(), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"last\": "
				+ ((session.getLast() == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getLast(), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"last2\": "
				+ ((session.getLast(1) == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getLast(1), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"last3\": "
				+ ((session.getLast(2) == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getLast(2), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"last_t\": "
				+ (((session_t != null) && (session_t.getLast() != ParserHelper.DDFAPI_NOVALUE)) ? ParserHelper
						.float2string(session_t.getLast(), this._symbolInfo.getBaseCode(), ParserHelper.PURE_DECIMAL)
						: "null")
				+ ", \"lastsize\": "
				+ ((session.getLastSize() == ParserHelper.DDFAPI_NOVALUE) ? "null" : session.getLastSize())
				+ ", \"tradetimestamp\": " + session.getTradeTimestamp() + ", \"settlement\": "
				+ ((session.getSettlement() == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getSettlement(), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"previous\": "
				+ ((session.getPrevious() == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: ParserHelper.float2string(session.getPrevious(), this._symbolInfo.getBaseCode(),
								ParserHelper.PURE_DECIMAL))
				+ ", \"volume\": "
				+ ((session.getVolume() == ParserHelper.DDFAPI_NOVALUE) ? "null" : session.getVolume())
				+ ", \"openinterest\": "
				+ ((this._previousSession.getOpenInterest() == ParserHelper.DDFAPI_NOVALUE) ? "null"
						: this._previousSession.getOpenInterest())
				+ ", \"numtrades\": " + session.getNumberOfTrades() + ", \"pricevolume\": " + ParserHelper.float2string(session.getPriceVolume(), 'A', ParserHelper.PURE_DECIMAL, false)
				+ ", \"timestamp\": " + session.getTimeInMillis());
		
		if ((session_t != null) && (session_t.getLast() != ParserHelper.DDFAPI_NOVALUE)) {
			sb.append(", \"t_session\" : { ");
			sb.append("\"last\": " + ParserHelper.float2string(session_t.getLast(), this._symbolInfo.getBaseCode(), ParserHelper.PURE_DECIMAL));
			sb.append(", \"lastsize\": " + ((session_t.getLastSize() == ParserHelper.DDFAPI_NOVALUE) ? "null" : session_t.getLastSize()));
			sb.append(", \"tradetimestamp\": " + session_t.getTradeTimestamp());
			sb.append(", \"timestamp\": " + session_t.getTimeInMillis());
			sb.append("}");
		}		
		
		Session previous_session = this._previousSession;

		sb.append(", " + "\"previous_session\": { ");
		sb.append("\"last\": " + ((previous_session.getLast() == ParserHelper.DDFAPI_NOVALUE) ? "null" : ParserHelper.float2string(previous_session.getLast(), this._symbolInfo.getBaseCode(), ParserHelper.PURE_DECIMAL)));
		sb.append(((previous_session.getOpen() == ParserHelper.DDFAPI_NOVALUE) ? "" : ",\"open\": " + ParserHelper.float2string(previous_session.getOpen(), this._symbolInfo.getBaseCode(), ParserHelper.PURE_DECIMAL)));
		sb.append(((previous_session.getHigh() == ParserHelper.DDFAPI_NOVALUE) ? "" : ",\"high\": " + ParserHelper.float2string(previous_session.getHigh(), this._symbolInfo.getBaseCode(), ParserHelper.PURE_DECIMAL)));
		sb.append(((previous_session.getLow() == ParserHelper.DDFAPI_NOVALUE) ? "" : ",\"low\": " + ParserHelper.float2string(previous_session.getLow(), this._symbolInfo.getBaseCode(), ParserHelper.PURE_DECIMAL)));
		sb.append(((previous_session.getPrevious() == ParserHelper.DDFAPI_NOVALUE) ? "" : ",\"previous\": " + ParserHelper.float2string(previous_session.getPrevious(), this._symbolInfo.getBaseCode(), ParserHelper.PURE_DECIMAL)));
		sb.append((previous_session.getVolume() == ParserHelper.DDFAPI_NOVALUE) ? "" : ",\"volume\": " + previous_session.getVolume());
		sb.append((previous_session.getOpenInterest() == ParserHelper.DDFAPI_NOVALUE) ? "" : ",\"openinterest\": " + previous_session.getOpenInterest());
		sb.append(",\"day\": " + ((previous_session.getDayCode() == '\0') ? "null" : "\"" + previous_session.getDayCode() + "\""));
		sb.append(",\"date\": " + ((previous_session.getDay() == null) ? "null" : "\"" + LocalDate.from(previous_session.getDay().getDate()).format(DateTimeFormatter.ISO_DATE) + "\""));
		
		sb.append(" }");
		
		sb.append("}");
		return sb.toString();
	}

	
	public XMLNode toXMLNode() {
		return toXMLNode(true);
	}

	
	/**
	 * Converts the Quote object into an XMLNode, which can then be used to
	 * bring the Quote into a textual form.
	 * 
	 * @param showBidAsk
	 *            Will add bid and ask in the Object
	 * @return XMLNode The XMLNode representing this Quote.
	 */
	
	public XMLNode toXMLNode(boolean showBidAsk) {
		XMLNode node = new XMLNode("QUOTE");
		node.setAttribute("symbol", _symbolInfo.getSymbol());
		node.setAttribute("name", _symbolInfo.getName());
		node.setAttribute("exchange", _symbolInfo.getExchange());
		node.setAttribute("basecode", "" + _symbolInfo.getBaseCode());
		node.setAttribute("pointvalue", "" + _symbolInfo.getPointValue());
		node.setAttribute("tickincrement", "" + _symbolInfo.getTickIncrement());

		if ((_ddfExchange != null) && (_ddfExchange.length() > 0))
			node.setAttribute("ddfexchange", _ddfExchange);

		if (_flag != '\0')
			node.setAttribute("flag", "" + _flag);

		if (_marketCondition != MarketConditionType.NORMAL)
			node.setAttribute("marketcondition", "" + _marketCondition.getCode());

		if (_lastUpdated > 0)
			node.setAttribute("lastupdate", (new DDFDate(_lastUpdated)).toDDFString());

		
		if (showBidAsk) {
			if (_bid != ParserHelper.DDFAPI_NOVALUE)
				node.setAttribute("bid", Integer.toString(ParserHelper.float2int(_symbolInfo.getUnitCode(), _bid)));
			if (_bidSize != ParserHelper.DDFAPI_NOVALUE)
				node.setAttribute("bidsize", "" + _bidSize);
			if (_ask != ParserHelper.DDFAPI_NOVALUE)
				node.setAttribute("ask", Integer.toString(ParserHelper.float2int(_symbolInfo.getUnitCode(), _ask)));
			if (_askSize != ParserHelper.DDFAPI_NOVALUE)
				node.setAttribute("asksize", "" + _askSize);
		}

		XMLNode n1 = _combinedSession.toXMLNode();
		n1.setAttribute("id", "combined");
		node.addNode(n1);

		XMLNode n2 = _previousSession.toXMLNode();
		n2.setAttribute("id", "previous");
		node.addNode(n2);

		for (Session session : _sessions) {
			XMLNode n = session.toXMLNode();
			n.setAttribute("id", "session_" + n.getAttribute("day") + "_" + n.getAttribute("session"));
			node.addNode(n);
		}

		return node;
	}

	/**
	 * Takes in an XMLNode object, and parses this into a Quote object.
	 * 
	 * @param node
	 *            XML Quote Object
	 * @return Quote
	 */
	public static Quote fromXMLNode(XMLNode node) {

		if (!node.getName().equals("QUOTE"))
			return null;

		Quote qte = new Quote(new SymbolInfo(node.getAttribute("symbol"), node.getAttribute("name"),
				node.getAttribute("exchange"), node.getAttribute("basecode").charAt(0),
				((node.getAttribute("pointvalue") != null) ? Float.parseFloat(node.getAttribute("pointvalue")) : 1.0f),
				((node.getAttribute("tickincrement") != null) ? Integer.parseInt(node.getAttribute("tickincrement"))
						: 1)));

		String s = node.getAttribute("ddfexchange");
		if (s != null)
			qte._ddfExchange = node.getAttribute("ddfexchange");

		s = node.getAttribute("flag");
		if ((s != null) && (s.length() > 0))
			qte._flag = s.charAt(0);

		s = node.getAttribute("marketcondition");
		if ((s != null) && (s.length() > 0))
			qte._marketCondition = MarketConditionType.getByCode(s.charAt(0));

		s = node.getAttribute("bid");
		if (s != null)
			qte._bid = ParserHelper.string2float(s, qte.getSymbolInfo().getBaseCode());

		s = node.getAttribute("bidsize");
		if (s != null)
			qte._bidSize = ParserHelper.string2int(s);

		s = node.getAttribute("ask");
		if (s != null)
			qte._ask = ParserHelper.string2float(s, qte.getSymbolInfo().getBaseCode());

		s = node.getAttribute("asksize");
		if (s != null)
			qte._askSize = ParserHelper.string2int(s);

		s = node.getAttribute("mode");
		if (s != null)
			qte._permission = s.charAt(0);

		s = node.getAttribute("lastupdate");
		if ((s != null) && (s.length() > 0))
			qte._lastUpdated = DDFDate.fromDDFString(s).getMillisCST();
		
		
		for (XMLNode n : node.getAllNodes("SESSION")) {
			Session session = new Session(qte);
			session.fromXMLNode(n);

			if (n.getAttribute("id").equals("combined"))
				qte._combinedSession = session;
			else if (n.getAttribute("id").equals("previous"))
				qte._previousSession = session;
			else
				qte._sessions.add(session);
		}
		return qte;
	}

	public boolean isTick() {
		return _message.getQuoteType().isTick();
	}

	public boolean isRefresh() {
		return _message.getQuoteType().isRefresh();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy