Draw Fibonacci Arcs
Asked Answered
J

1

7

I am attempting to create an application that draws Fibonacci Arcs similar to these. Stock Chart Fibonacci Arcs

However, I'd like full circles instead of arcs, and I'd like to draw more than the three Fibonacci lines shown in the picture. I've created an application using JFreeChart to attempt to accomplish this. However, here is the result when trying to draw the same arcs (but as circles) shown in the previous picture. My app zoomed in

Initially, it just looks wrong, but when I zoom out, it is indeed a circle, but it's way too big. enter image description here

To calculate the arcs, you draw a line, then take a Fibonacci ratio - let's use .381 for example - the percentage of that line. If you look at the first picture, you'll see the innermost arc intersects the line at .381% the distance of the line from the centre of the circle. First I calculate this point. Then I construct a line from the .381% point to the centre. Then I take the distance of this line, which should be the radius. Then I use this radius to draw the circle.

Here's the code to calculate the radius. Where stop and start are the stop and start points of the line drawn.

multiplier = ratio38Value + i;
diffx = (stop.getX() - start.getX()) * multiplier;
diffy = (stop.getY() - start.getY()) * multiplier;
xValue = start.getX() + diffx;
yValue = start.getY() + diffy;
point = new Point(xValue, yValue);
lineSegment = new Line(point, stop);
radius = lineSegment.getDistance();
circle = new Circle(stop.getX(), stop.getY(), radius);
circles.add(circle);

Here is the code to calculate the distance of a line

public double getDistance(){
    double x = Math.pow(endPoint.getX() - startPoint.getX(), 2);
    double y = Math.pow(endPoint.getY() - startPoint.getY(), 2);
    return Math.sqrt(x + y);

}

I get back a list of circle objects (this is an object I created that holds the radius and centre point) one for each circle that needs to be drawn and then draw them.

List<Circle> circles = fibonacciCalculations.getFibonacciArcs(startPoint, endPoint);
if(circles != null)
{
    for (Circle circle : circles){
        double xCenter = circle.getX();
        double yCenter = circle.getY();
        double radius = circle.getRadius();
        plot.addAnnotation(new XYShapeAnnotation(new Ellipse2D.Double(xCenter - radius, yCenter - radius, radius + radius, radius + radius)));
    }
}

I think the issue has something to do with how the x-axis of time and the y axis of price doesn't exactly correlate. What I mean is, if the radius is 20, you'll be going 20 units away from the centre at each point. So say you're stock price is only 5 dollars, at your lowest point you will then be at -15. If that is the case, I have no idea how to fix it. But it also could be some error in my logic. Any ideas would be appreciated.

EDIT: While the bars look like they may be weekly bars in the first picture, they are indeed daily bars. Also, I have already converted the coordinates from data space to x y coordinates. I use this code below to do that.

@Override
public void chartMouseMoved(ChartMouseEvent event) {
    Rectangle2D dataArea = cp.getScreenDataArea();
    JFreeChart chart = event.getChart();
    XYPlot plot = (XYPlot) chart.getPlot();
    ValueAxis xAxis = plot.getDomainAxis();
    ValueAxis yAxis = plot.getRangeAxis();
    double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea, 
            RectangleEdge.BOTTOM);
    double y = yAxis.java2DToValue(event.getTrigger().getY(), dataArea, 
            RectangleEdge.LEFT);
Jannette answered 26/4, 2017 at 23:55 Comment(4)
Yeah, the scale is throwing the image off so it's hard to know what's going on. What you can do is scale your own scale to the same scale as the first image. For the x axis, the scale's unit is weeks. In Count how many units are in between the center of circle and the intersection to the line, and then scale your scale using the calculated proportion. The units on both charts should match. Do same for y axis.Volleyball
@NickZiebert is correct: the XYShapeAnnotation coordinates are in "data space," for example.Twelvetone
I would like to help you debugging this but you do not provide enough information - or it would just take too much time. Guesses: incorrect ratio, your line is just longer then you think, mixed start/stop, space conversion. Could you provide a complete code example - maybe on github? Or could you provide some real numbers?Podolsk
Thanks @A.Binzxxxxxx. I had figured it out right before you sent this message though.Jannette
J
0

I'm not sure of the proper terminology, so lets call the actual (x,y) coordinates that represent where you are on your monitor "screen space" and let's call the (x,y) coordinates of the chart "chart space".

My issue was I was converting the points from screen space to chart space and then calculating my points. Instead, I should have calculated all my points in screen space, and then converted each calculated point to chart space.

Where i is the amount of groups of arcs I want to draw. (i = 0, then I am drawing circles for the 38, 50, 62 ratios, i = 1 then I'm drawing circles for the -1.68, -1.50...1.50, 1.68 ratios) I use this code to get my points that are a given ratio between the center and the starting point.

            multiplier = ratio62Value + i;
            diffx = (stop.getX() - start.getX()) * multiplier;
            diffy = (stop.getY() - start.getY()) * multiplier;
            xValue = start.getX() + diffx;
            yValue = start.getY() + diffy;
            point = new Point(xValue, yValue);
            line = new Line(point, stop);
            line.calculateCirclePoints();

Here is the method to calculate the points on the circle. Where, endPoint is the center point, and the radius is the distance from the start point to the end point.

public void calculateCirclePoints(){
    double radius = getDistance();
    double radians;
    double x;
    double y;
    Point currentPoint;

    for (int degrees = 0; degrees <= 360; degrees += 1){
        radians = Math.toRadians(degrees);
        x = endPoint.getX() + (radius * Math.cos(radians));
        y = endPoint.getY() + (radius * Math.sin(radians));
        currentPoint = new Point(x, y);
        points.add(currentPoint);
    }
}

Lastly, I convert all of these points to chart space, and draw them on the chart.

public static Point converPointTo2D(Point point, Rectangle2D dataArea, XYPlot plot){
    double x;
    double y;

    CustomNumberAxis xAxis = (CustomNumberAxis) plot.getDomainAxis();
    CustomNumberAxis yAxis = (CustomNumberAxis) plot.getRangeAxis();

    x = xAxis.java2DToValue(point.getX(), dataArea, 
            RectangleEdge.BOTTOM);
    y = yAxis.java2DToValue(point.getY(), dataArea, 
            RectangleEdge.RIGHT);

    return new Point(x, y);
}

enter image description here

One point to note, the radius of the circles is dependent on how much of a specific chart you're showing. A circle drawn on a 1 year chart from point a to point b will be smaller than a circle drawn on a 5 year chart from those same points.

Jannette answered 13/5, 2017 at 14:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.