Skip to content

Commit

Permalink
Added the StockDrawUtil class
Browse files Browse the repository at this point in the history
Created tooltips for candles
Added price line markers
Added a small slider to manually adjust the current datetime by +- 10 seconds
  • Loading branch information
evanobenauer committed Jul 7, 2023
1 parent 23f2d32 commit cc8fde8
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 35 deletions.
19 changes: 15 additions & 4 deletions src/main/java/com/ejo/stockdownloader/data/Stock.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ public void updateLivePriceData() {

/**
* Updates the splitting of the stock into candles based on the TimeFrame of the stock selected. This method adds an entry to the historical data HashMap and then resets the livedata to the current price
* TODO: The issue with segmentation is of when the next candle opens. For tradingview, the candle opens a tick AFTER the close, causing a difference
* MY data opens and closes at the same time, which is different. Tradingview closes at 59 and opens at 0. My data closes at 0 and opens at 0
*
*/
public void updateSegmentation() {
if (shouldOpen()) {
Expand All @@ -153,7 +156,7 @@ public void updateSegmentation() {
//Save Live Data as Historical
String[] timeFrameData = {String.valueOf(getOpen()),String.valueOf(getPrice()),String.valueOf(getMin()),String.valueOf(getMax())};
DateTime previousOpen = new DateTime(ct.getYearInt(),ct.getMonthInt(),ct.getDayInt(),ct.getHourInt(),ct.getMinuteInt(),ct.getSecondInt() - getTimeFrame().getSeconds());
dataHash.put(previousOpen.getDateTimeID(),timeFrameData);
if (getPrice() != -1) dataHash.put(previousOpen.getDateTimeID(),timeFrameData);

//Reset Live Data for next Candle
this.startTime = ct;
Expand All @@ -172,11 +175,19 @@ public void updateSegmentation() {
public void updateSegmentationPercentage() {
//TODO: Fix for all timeframes over 1min
DateTime ct = StockUtil.getAdjustedCurrentTime();
double totalPercent = 0;

//Second Percent
double sec = ct.getSecondInt();
if (ct.getSecondInt() % getTimeFrame().getSeconds() == 0) sec *= ((double) getTimeFrame().getSeconds() / ct.getSecondInt());
double percent = sec / getTimeFrame().getSeconds();
percent -= Math.floor(percent);
getClosePercent().set(percent);
double secPercent = sec / getTimeFrame().getSeconds();
secPercent -= Math.floor(secPercent);
totalPercent += secPercent;

//Minute Percent
//TODO: Add

getClosePercent().set(totalPercent);
}


Expand Down
71 changes: 41 additions & 30 deletions src/main/java/com/ejo/stockdownloader/scenes/DownloadScene.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package com.ejo.stockdownloader.scenes;

import com.ejo.glowlib.math.MathE;
import com.ejo.glowlib.math.Vector;
import com.ejo.glowlib.misc.ColorE;
import com.ejo.glowlib.misc.Container;
import com.ejo.glowlib.time.DateTime;
import com.ejo.glowlib.time.StopWatch;
import com.ejo.glowui.scene.Scene;
import com.ejo.glowui.scene.elements.ProgressBarUI;
import com.ejo.glowui.scene.elements.TextUI;
import com.ejo.glowui.scene.elements.widget.ButtonUI;
import com.ejo.glowui.scene.elements.widget.SliderUI;
import com.ejo.glowui.util.QuickDraw;
import com.ejo.stockdownloader.data.Stock;
import com.ejo.stockdownloader.util.StockDrawUtil;
import com.ejo.stockdownloader.util.StockUtil;
import com.ejo.stockdownloader.render.CandleUI;

Expand All @@ -20,10 +21,13 @@

public class DownloadScene extends Scene {

//TODO: Add optional candle rendering mode. One mode is the current one, one mode is the current candle ONLY?

private final Stock stock;

private final ProgressBarUI<Double> candlePercent;
private final SliderUI<Double> scaleSlider;
private final SliderUI<Integer> secAdjust;
private final ButtonUI saveButton;
private final ButtonUI exitButton;

Expand All @@ -35,6 +39,7 @@ public DownloadScene(Stock stock) {
addElements(
candlePercent = new ProgressBarUI<>(this, Vector.NULL, new Vector(200, 20), stock.getClosePercent(), 0, 1, ColorE.BLUE),
scaleSlider = new SliderUI<>(this, "Scale", Vector.NULL, new Vector(200, 20), ColorE.BLUE, scaleY, 0d, 2000d, 10d, SliderUI.Type.FLOAT, true),
secAdjust = new SliderUI<>(this, "Seconds",Vector.NULL, new Vector(65, 10), ColorE.BLUE, StockUtil.SECOND_ADJUST, -10, 10, 1, SliderUI.Type.INTEGER, true),
saveButton = new ButtonUI(this, "Force Save", Vector.NULL, new Vector(100, 40), new ColorE(0, 125, 200, 200), stock::saveHistoricalData),
exitButton = new ButtonUI(this, Vector.NULL, new Vector(15, 15), new ColorE(200, 0, 0, 255), () -> getWindow().setScene(new TitleScene()))
);
Expand All @@ -45,12 +50,6 @@ public void draw() {
//Draw Background
QuickDraw.drawRect(this, Vector.NULL, getWindow().getSize(), new ColorE(50, 50, 50, 255));

//Draw Stock Ticker
QuickDraw.drawText(this, "Downloading: " + stock.getTicker() + "-" + stock.getTimeFrame().getTag(), new Font("Arial", Font.PLAIN, 10), new Vector(1, 1), ColorE.WHITE);

//Draw FPS/TPS
QuickDraw.drawFPSTPS(this, new Vector(1, 11), 10, false);

//Define Candle List
ArrayList<CandleUI> candleList = new ArrayList<>();

Expand All @@ -63,49 +62,57 @@ public void draw() {
CandleUI currentCandle = new CandleUI(this, stock, getWindow().getSize().getX() - width - spacing, getWindow().getSize().getY() / 2, stock.getPrice(), width, scale);
candleList.add(currentCandle);

//Draw Price Line
QuickDraw.drawRect(this, new Vector(0, getWindow().getSize().getY() / 2), new Vector(getWindow().getSize().getX(), .5), new ColorE(currentCandle.getColor().getRed(), currentCandle.getColor().getGreen(), currentCandle.getColor().getBlue(), 70));

//Draw Cross hair Soon
//QuickDraw.drawRect();

//Update Segmentation to prevent spaced transition
if (stock.shouldOpen()) stock.updateSegmentation();

//Create Historical Candles
DateTime ct = StockUtil.getAdjustedCurrentTime();
for (int i = 1; i < (int) (getWindow().getSize().getX() / 18) + 1; i++) {
for (int i = 1; i < (int) (getWindow().getSize().getX() / 18) + 1; i++) { //Causes High Power Usage
DateTime time = new DateTime(ct.getYearInt(), ct.getMonthInt(), ct.getDayInt(), ct.getHourInt(), ct.getMinuteInt(), stock.getStartTime().getSecondInt() - stock.getTimeFrame().getSeconds() * i);
CandleUI candle = new CandleUI(this, stock, time, currentCandle.getPos().getX() - (spacing + width) * i, getWindow().getSize().getY() / 2, stock.getPrice(), width, scale);
candleList.add(candle);
}

//Draw and Tick All Candles
for (CandleUI candle : candleList) {
if (candle.getStock().getOpen() == -1) continue;
if (candle.getStock().getOpen(candle.getDateTime()) == -1) continue;
candle.draw();
candle.tick(); //For Mouse Over Data
if (candle.isMouseOver()) {
int size = 10;
int x = 2;
int y = (int) (getWindow().getSize().getY() - 105);
QuickDraw.drawText(this, "Open:" + stock.getOpen(candle.getDateTime()), new Font("Arial", Font.PLAIN, size), new Vector(x, y), ColorE.WHITE);
QuickDraw.drawText(this, "Close:" + stock.getClose(candle.getDateTime()), new Font("Arial", Font.PLAIN, size), new Vector(x, y + size), ColorE.WHITE);
QuickDraw.drawText(this, "Min:" + stock.getMin(candle.getDateTime()), new Font("Arial", Font.PLAIN, size), new Vector(x, y + size * 2), ColorE.WHITE);
QuickDraw.drawText(this, "Max:" + stock.getMax(candle.getDateTime()), new Font("Arial", Font.PLAIN, size), new Vector(x, y + size * 3), ColorE.WHITE);
}
}

//Draw Tooltip
for (CandleUI candle : candleList) {
if (candle.getStock().getOpen(candle.getDateTime()) == -1) continue;
if (candle.isMouseOver()) StockDrawUtil.drawCandleTooltip(candle,getWindow().getMousePos());
}

//Draw Price Line and Tag
if (stock.shouldUpdate()) {
QuickDraw.drawRect(this, new Vector(0, getWindow().getSize().getY() / 2), new Vector(getWindow().getSize().getX(), .5), new ColorE(currentCandle.getColor().getRed(), currentCandle.getColor().getGreen(), currentCandle.getColor().getBlue(), 70));
double height = 15;
QuickDraw.drawRect(this, new Vector(0, getWindow().getSize().getY() / 2 - height / 2), new Vector(36, height), new ColorE(currentCandle.getColor().getRed(), currentCandle.getColor().getGreen(), currentCandle.getColor().getBlue(), 200));
QuickDraw.drawText(this, String.valueOf(MathE.roundDouble(stock.getPrice(), 2)), new Font("Arial", Font.PLAIN, 10), new Vector(2, getWindow().getSize().getY() / 2 - height / 2), ColorE.WHITE);

//Draw Hover Price Line and Tag
QuickDraw.drawRect(this, new Vector(0, getWindow().getMousePos().getY()), new Vector(getWindow().getSize().getX(), .5), ColorE.GRAY);
QuickDraw.drawRect(this, new Vector(0, getWindow().getMousePos().getY() - height / 2), new Vector(36, height), new ColorE(125, 125, 125, 200));
double yPrice = (currentCandle.getFocusY() - getWindow().getMousePos().getY()) / currentCandle.getScale().getY() + currentCandle.getFocusPrice();
QuickDraw.drawText(this, String.valueOf(MathE.roundDouble(yPrice, 2)), new Font("Arial", Font.PLAIN, 10), new Vector(2, getWindow().getMousePos().getY() - height / 2), ColorE.WHITE);
}

//Draw Waiting Text
if (!stock.shouldUpdate()) {
new TextUI(this, "Waiting for next candle!", "Arial", 20, Vector.NULL, ColorE.WHITE).drawCentered(getWindow().getSize());
QuickDraw.drawTextCentered(this,"Waiting for next candle!", new Font("Arial",Font.PLAIN,20),Vector.NULL,getWindow().getSize(),ColorE.WHITE);
}

//Draw Bottom Bar
QuickDraw.drawRect(this, new Vector(0, getWindow().getSize().getY() - 60), new Vector(getWindow().getSize().getX(), 60), new ColorE(25, 25, 25, 255));

super.draw();

//Draw Stock Ticker
QuickDraw.drawText(this, "Downloading: " + stock.getTicker() + "-" + stock.getTimeFrame().getTag(), new Font("Arial", Font.PLAIN, 10), new Vector(16, 1), ColorE.WHITE);

//Draw FPS/TPS
QuickDraw.drawFPSTPS(this, new Vector(1, 14), 10, false);

//Draw X for Exit Button
QuickDraw.drawText(this,"X",new Font("Arial",Font.PLAIN,14),exitButton.getPos().getAdded(3,0),ColorE.WHITE);

Expand All @@ -120,11 +127,15 @@ public void draw() {
public void tick() {
super.tick();

//Update Segmentation to prevent spaced transition
if (stock.shouldOpen()) stock.updateSegmentation();

//Update anchored elements
candlePercent.setPos(new Vector(10, getWindow().getSize().getY() - candlePercent.getSize().getY() - 20));
scaleSlider.setPos(new Vector(getWindow().getSize().getX() - scaleSlider.getSize().getX() - 10, getWindow().getSize().getY() - scaleSlider.getSize().getY() - 20));
saveButton.setPos(new Vector(getWindow().getSize().getX() - saveButton.getSize().getX() - 20, 10));
exitButton.setPos(new Vector(getWindow().getSize().getX(), 0).getAdded(-exitButton.getSize().getX(), 0));
secAdjust.setPos(new Vector(145, getWindow().getSize().getY() - secAdjust.getSize().getY() - 42));
saveButton.setPos(new Vector(getWindow().getSize().getX() - saveButton.getSize().getX() - 2, 5));
exitButton.setPos(new Vector(0, 0));

//Update all stock data
stock.updateData(0.5);
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/com/ejo/stockdownloader/util/StockDrawUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.ejo.stockdownloader.util;

import com.ejo.glowlib.math.MathE;
import com.ejo.glowlib.math.Vector;
import com.ejo.glowlib.misc.ColorE;
import com.ejo.glowui.util.QuickDraw;
import com.ejo.stockdownloader.data.Stock;
import com.ejo.stockdownloader.render.CandleUI;

import java.awt.*;

public class StockDrawUtil {

public static void drawCandleTooltip(CandleUI candle, Vector mousePos) {
Stock stock = candle.getStock();
int size = 10;
double x = mousePos.getX() - 60;
double y = mousePos.getY() - size * 4 - 5;

if (x < 0) {
x = 0;
mousePos = new Vector(60,mousePos.getY());
}

if (y < 0) {
y = 0;
mousePos = new Vector(mousePos.getX(),size * 4 + 5);
}

double open = MathE.roundDouble(stock.getOpen(candle.getDateTime()), 2);
double close = MathE.roundDouble(stock.getClose(candle.getDateTime()), 2);
double min = MathE.roundDouble(stock.getMin(candle.getDateTime()), 2);
double max = MathE.roundDouble(stock.getMax(candle.getDateTime()), 2);

QuickDraw.drawRect(candle.getScene(), new Vector(x - 2, y), new Vector(mousePos.getX() - x + 2, mousePos.getY() - y - 1), new ColorE(0, 125, 200, 200));

QuickDraw.drawText(candle.getScene(), "Open:" + open, new Font("Arial", Font.PLAIN, size), new Vector(x, y), ColorE.WHITE);
QuickDraw.drawText(candle.getScene(), "Close:" + close, new Font("Arial", Font.PLAIN, size), new Vector(x, y + size), ColorE.WHITE);
QuickDraw.drawText(candle.getScene(), "Min:" + min, new Font("Arial", Font.PLAIN, size), new Vector(x, y + size * 2), ColorE.WHITE);
QuickDraw.drawText(candle.getScene(), "Max:" + max, new Font("Arial", Font.PLAIN, size), new Vector(x, y + size * 3), ColorE.WHITE);

}
}
5 changes: 4 additions & 1 deletion src/main/java/com/ejo/stockdownloader/util/StockUtil.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ejo.stockdownloader.util;

import com.ejo.glowlib.misc.Container;
import com.ejo.glowlib.time.DateTime;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
Expand All @@ -13,6 +14,8 @@

public class StockUtil {

public static final Container<Integer> SECOND_ADJUST = new Container<>(-2);

/**
* This method downloads live stock data from Yahoo Finance. This is how we get the live data for the stock and proceed with downloading our numbers. "raw" is the raw data, "fmt" is the formatted data
* @return
Expand Down Expand Up @@ -40,7 +43,7 @@ public static boolean isTradingHours(DateTime currentTime) {

public static DateTime getAdjustedCurrentTime() {
DateTime ct = DateTime.getCurrentDateTime();
return new DateTime(ct.getYearInt(), ct.getMonthInt(), ct.getDayInt(), ct.getHourInt(),ct.getMinuteInt(),ct.getSecondInt() - 2);
return new DateTime(ct.getYearInt(), ct.getMonthInt(), ct.getDayInt(), ct.getHourInt(),ct.getMinuteInt(),ct.getSecondInt() + SECOND_ADJUST.get());
}

}

0 comments on commit cc8fde8

Please sign in to comment.