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

de.gsi.chart.renderer.spi.financial.PositionFinancialRendererPaintAfterEP Maven / Gradle / Ivy

package de.gsi.chart.renderer.spi.financial;

import static de.gsi.chart.renderer.spi.financial.css.FinancialCss.*;

import java.util.ArrayList;
import java.util.List;

import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;

import de.gsi.chart.XYChart;
import de.gsi.chart.axes.Axis;
import de.gsi.chart.renderer.spi.financial.service.DataSetAware;
import de.gsi.chart.renderer.spi.financial.service.OhlcvRendererEpData;
import de.gsi.chart.renderer.spi.financial.service.RendererPaintAfterEP;
import de.gsi.chart.utils.StyleParser;
import de.gsi.dataset.DataSet;

/**
 * Position renderer PaintAfter Extension Point
 *

* A position is the amount of a security, asset, or property that is owned (or sold short) by some individual or other entity. * A trader or investor takes a position when they make a purchase through a buy order, signaling bullish intent; or if they sell short securities with bearish intent. * Opening a new position is ultimately followed at some point in the future by exiting or closing the position. *

* Positions come in two main types. Long positions are most common and involve owning a security or contract. Long positions gain when there is an increase in price and lose when there is a decrease. * Short positions, in contrast, profit when the underlying security falls in price. A short often involves securities that are borrowed and then sold, * to be bought back hopefully at a lower price. Depending on market trends, movements and fluctuations, a position can be profitable or unprofitable. * Restating the value of an open position to reflect its actual current value is referred to in the industry as “mark-to-market.” *

* In order to get out of an open position, it needs to be closed. A long will sell to close; a short will buy to close. * Closing a position thus involves the opposite action that opened the position in the first place. * The difference between the price at which the position in a security was opened and the price at which it was closed represents * the gross profit or loss (PL) on that position. *

* The visualization of positions are implemented by interface RendererPaintAfterEP. This component is PaintAfter extension point for renders HighLow, CandleStick, and others renderers. * This component has to be add to the extension point method of described renderers. *

* This component needs to required inputs. The instance chart for axis information and the dataset which contains positions data. * The implementation of the position dataset has to implement: *

    *
  • PositionRenderedAware interface which provides simplified structures of positions for required timestamp (in seconds or indices), and *
  • conversion / mapping of your position domain objects to simplified domain object PositionRendered which is handled by this component. *
* * @see Position Investopedia * @author afischer */ @SuppressWarnings({ "PMD.NPathComplexity" }) public class PositionFinancialRendererPaintAfterEP implements RendererPaintAfterEP, DataSetAware { protected final DataSet ds; protected final XYChart chart; protected final Axis xAxis; protected final Axis yAxis; private Color positionTriangleLongColor; private Color positionTriangleShortColor; private Color positionTriangleExitColor; private Color positionArrowLongColor; private Color positionArrowShortColor; private Color positionArrowExitColor; private Color positionLabelTradeDescriptionColor; private Color positionOrderLinkageProfitColor; private Color positionOrderLinkageLossColor; private String positionLabelLongText; private String positionLabelShortText; private double positionPaintMainRatio; private double positionOrderLinkageLineDash; private double positionOrderLinkageLineWidth; public PositionFinancialRendererPaintAfterEP(final DataSet positionDataSet, final XYChart chart) { this.ds = positionDataSet; this.chart = chart; xAxis = chart.getXAxis(); yAxis = chart.getYAxis(); if (!(positionDataSet instanceof PositionRenderedAware)) { throw new IllegalArgumentException("The position dataset has to implement PositionRenderedAware interface"); } } @Override public DataSet getDataSet() { return ds; } protected void initByDatasetFxStyle() { String style = ds.getStyle(); positionTriangleLongColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_TRIANGLE_LONG_COLOR, Color.GREEN); positionTriangleShortColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_TRIANGLE_SHORT_COLOR, Color.RED); positionTriangleExitColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_TRIANGLE_EXIT_COLOR, Color.BLACK); positionArrowLongColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_ARROW_LONG_COLOR, Color.GREEN); positionArrowShortColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_ARROW_SHORT_COLOR, Color.RED); positionArrowExitColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_ARROW_EXIT_COLOR, Color.BLACK); positionLabelTradeDescriptionColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_LABEL_TRADE_DESCRIPTION_COLOR, Color.BLACK); positionOrderLinkageProfitColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_ORDER_LINKAGE_PROFIT_COLOR, Color.GREEN); positionOrderLinkageLossColor = StyleParser.getColorPropertyValue(style, DATASET_POSITION_ORDER_LINKAGE_LOSS_COLOR, Color.RED); positionLabelLongText = StyleParser.getPropertyValue(style, DATASET_POSITION_LABEL_LONG_TEXT, "Buy%n%1.0f%n(%1.1f)"); positionLabelShortText = StyleParser.getPropertyValue(style, DATASET_POSITION_LABEL_SHORT_TEXT, "Sell%n%1.0f%n(%1.1f)"); positionOrderLinkageLineDash = StyleParser.getFloatingDecimalPropertyValue(style, DATASET_POSITION_ORDER_LINKAGE_LINE_DASH, 8.0d); positionOrderLinkageLineWidth = StyleParser.getFloatingDecimalPropertyValue(style, DATASET_POSITION_ORDER_LINKAGE_LINE_WIDTH, 2.0d); positionPaintMainRatio = StyleParser.getFloatingDecimalPropertyValue(style, DATASET_POSITION_PAINT_MAIN_RATIO, 5.157d); } @Override public void paintAfter(OhlcvRendererEpData d) { if (d.index == d.minIndex) { initByDatasetFxStyle(); } long xcorr = Math.round(d.ohlcvItem.getTimeStamp().getTime() / 1000.0); PositionRendered position = ((PositionRenderedAware) ds).getPositionByTime(xcorr); if (position == null) return; d.gc.save(); // compute constants double x0 = d.xCenter; double yPrice = yAxis.getDisplayPosition(position.price); double ratio = Math.pow(d.barWidth, 0.25) * positionPaintMainRatio; double arrowSize = ratio * 0.25; // draw triangle d.gc.setStroke(Color.BLACK); d.gc.setLineWidth(1.0); if (position.entryExit == 1) { // entry d.gc.setFill(position.posType > 0 ? positionTriangleLongColor : positionTriangleShortColor); drawTriangle(d, x0, yPrice, ratio, -1.0); } else { // exit (single exit color) d.gc.setFill(positionTriangleExitColor); drawTriangle(d, x0, yPrice, ratio, 1.0); } // draw arrows if (position.entryExit == 1) { // entry if (position.posType > 0) { // long d.gc.setFill(positionArrowLongColor); drawArrow(d, x0, d.yLow + ratio, arrowSize, 1.0); } else { // short d.gc.setFill(positionArrowShortColor); drawArrow(d, x0, d.yHigh - ratio, arrowSize, -1.0); } } else { // exit d.gc.setFill(positionArrowExitColor); if (position.posType > 0) { // long exit drawArrow(d, x0, d.yHigh - ratio, arrowSize, -1.0); } else { // short exit drawArrow(d, x0, d.yLow + ratio, arrowSize, 1.0); } } // draw text trade description d.gc.setStroke(positionLabelTradeDescriptionColor); d.gc.setFill(positionLabelTradeDescriptionColor); d.gc.setFont(new Font(1.5 * ratio)); d.gc.setTextAlign(TextAlignment.CENTER); if ((position.posType > 0 && position.entryExit == 1) || (position.posType < 0 && position.entryExit != 1)) { // long String label = String.format(positionLabelLongText, position.quantity, position.price); d.gc.fillText(label, x0, d.yLow + 6.0 * ratio); } else { // short String label = String.format(positionLabelShortText, -position.quantity, position.price); d.gc.fillText(label, x0, d.yHigh - 9.0 * ratio); } // draw linkages with entries if (position.entryExit != 1) { for (List joinedEntry : position.joinedEntries) { double xe0 = xAxis.getDisplayPosition(joinedEntry.get(0)); double ye1 = yAxis.getDisplayPosition(joinedEntry.get(1)); d.gc.setStroke(joinedEntry.get(2) > 0 ? positionOrderLinkageProfitColor : positionOrderLinkageLossColor); d.gc.setLineWidth(positionOrderLinkageLineWidth); d.gc.setLineDashes(positionOrderLinkageLineDash); d.gc.strokeLine(x0, yPrice, xe0, ye1); } } d.gc.restore(); } protected void drawArrow(OhlcvRendererEpData d, double x0, double start, double ratio, double sign) { d.gc.fillPolygon(new double[] { x0, x0 - 3.0 * ratio, x0 - 1.5 * ratio, x0 - 1.5 * ratio, x0 + 1.5 * ratio, x0 + 1.5 * ratio, x0 + 3.0 * ratio, x0 }, new double[] { start, start + sign * 3.0 * ratio, start + sign * 3.0 * ratio, start + sign * 9.0 * ratio, start + sign * 9.0 * ratio, start + sign * 3.0 * ratio, start + sign * 3.0 * ratio, start }, 8); } protected void drawTriangle(OhlcvRendererEpData d, double x0, double yPrice, double trSize, double sign) { d.gc.fillPolygon(new double[] { x0, x0 + sign * trSize, x0 + sign * trSize, x0 }, new double[] { yPrice, yPrice + trSize, yPrice - trSize, yPrice }, 4); } /** * API which has to be implemented by DataSet. * The simple dimensional dataset cannot be used for this complex structure. */ public interface PositionRenderedAware { PositionRendered getPositionByTime(long timestamp); } /** * API Domain Object: PositionRendered shared object is smallest simplification for visualization of positions structure. */ public static class PositionRendered implements Comparable { public long positionId; // unique identification of position ID public long index; // unique indices of position, coordination (if time - defined in seconds) public int entryExit; // 1 = entry, 2 = exit public double quantity; // contracts, shares public int posType; // +1 = long / -1 = short public double price; // avgFilled price public boolean closed; // position is closed public List> joinedEntries = new ArrayList<>(); // each row includes 1.joined entry index, 2.price value for actual exit and 3.profit +1/loss -1 (linkages) @Override public int compareTo(PositionRendered o) { return Double.compare(index, o.index); } @Override public String toString() { return "PositionRendered{" + "positionId=" + positionId + ", index=" + index + ", entryExit=" + entryExit + ", quantity=" + quantity + ", posType=" + posType + ", price=" + price + ", closed=" + closed + ", joinedEntries=" + joinedEntries + '}'; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy