swaschke/pypnf

Can you please add a function to get Price Objective after chart generated?

Opened this issue · 13 comments

PnFG commented

Great project! Can you please add a function to call after PnF chart is generated to get the next Price Objective - with configurable method like using 3 squares reversal method, as in chart below.

Preferably it returns Price Objective as float, Bullish or Bearish (strings?). If practical Confidence (Met, Tentative, etc) would be great too.

Is that doable?

Screenshot 2024-04-13 at 1 38 52 PM
PnFG commented

I should have added https://chartschool.stockcharts.com/table-of-contents/chart-analysis/point-and-figure-charts/p-and-f-price-objectives/p-and-f-price-objectives-breakout-and-reversal-method that outlines the logic to do so.

Adding LLM assisted resources informed by that page:

Q: Please translate the rules described in https://chartschool.stockcharts.com/table-of-contents/chart-analysis/point-and-figure-charts/p-and-f-price-objectives/p-and-f-price-objectives-breakout-and-reversal-method to determine Price Objectives in Point and Figure Charts into straightforward If Then Else statements that can be coded in any programming language.

A: Based on the content of the web page you are viewing, here are the If-Then-Else statements for determining Price Objectives in Point and Figure (P&F) Charts:

  • Identify Signal Type:

    • If the active signal is a P&F buy signal, then calculate a Bullish Price Objective.
    • Else if the active signal is a P&F sell signal, then calculate a Bearish Price Objective.
  • Breakout Method - Bullish:

    • If using the Breakout Method and the active signal is a P&F buy signal:
      • Find the most recent P&F sell signal.
      • Identify the Measure Column that reversed the P&F sell signal.
      • Calculate the height of the Measure Column.
      • Multiply the height by the box reversal amount.
      • Add the result to the low of the column before the Measure Column to get the Bullish Price Objective.
  • Breakout Method - Bearish:

    • If using the Breakout Method and the active signal is a P&F sell signal:
      • Find the most recent P&F buy signal
      • Identify the Measure Column that reversed the P&F buy signal.
      • Calculate the height of the Measure Column.
      • Multiply the height by 2/3 of the box reversal amount.
      • Subtract the result from the high of the column before the Measure Column to get the Bearish Price Objective.
  • Reversal Method - Bullish:

    • If using the Reversal Method and the active signal is a P&F buy signal:
      • Find the most recent P&F sell signal.
      • The X-Column next to the sell signal column becomes the Measure Column.
      • Calculate the height of the Measure Column.
      • Multiply the height by the box reversal amount.
      • Add the result to the low of the column before the Measure Column to get the Bullish Price Objective.
  • Reversal Method - Bearish:

    • If using the Reversal Method and the active signal is a P&F sell signal:
      • Find the most recent P&F buy signal.
      • The O-Column next to the buy signal column becomes the Measure Column.
      • Calculate the height of the Measure Column.
      • Multiply the height by 2/3 of the box reversal amount.
      • Subtract the result from the high of the column before the Measure Column to get the Bearish Price Objective.

These statements can be adapted into any programming language to automate the calculation of Price Objectives in P&F Charts. Remember to handle different scaling methods and box sizes as they can affect the calculations.

Q: Please propose changes to https://github.com/fivethreeo/pypnf/blob/patterns/pypnf/chart.py to add identifying Price Objectives to its generated PnF Charts using prior If Then Else statements.

A: Sure, I can help with that. Here's a high-level overview of the changes you might need to make to the chart.py file in the pypnf repository to add the functionality of identifying Price Objectives in Point and Figure Charts.
First, you'll need to add new methods to calculate the Bullish and Bearish Price Objectives based on the If-Then-Else statements I provided earlier.

Here's a rough idea of how you might implement these methods:

class Chart:
    # existing code...
    def calculate_bullish_price_objective(self):
        # If the active signal is a P&F buy signal
        if self.active_signal == 'buy':
            # Find the most recent P&F sell signal
            sell_signal = self.find_most_recent_sell_signal()
            # Identify the Measure Column that reversed the P&F sell signal
            measure_column = self.identify_measure_column(sell_signal)
            # Calculate the height of the Measure Column
            height = self.calculate_height(measure_column)
            # Multiply the height by the box reversal amount
            result = height * self.box_reversal_amount
            # Add the result to the low of the column before the Measure Column to get the Bullish Price Objective
            bullish_price_objective = result + self.get_low_of_column_before(measure_column)
            return bullish_price_objective

    def calculate_bearish_price_objective(self):
        # If the active signal is a P&F sell signal
        if self.active_signal == 'sell':
            # Find the most recent P&F buy signal
            buy_signal = self.find_most_recent_buy_signal()
            # Identify the Measure Column that reversed the P&F buy signal
            measure_column = self.identify_measure_column(buy_signal)
            # Calculate the height of the Measure Column
            height = self.calculate_height(measure_column)
            # Multiply the height by 2/3 of the box reversal amount
            result = height * (2/3) * self.box_reversal_amount
            # Subtract the result from the high of the column before the Measure Column to get the Bearish Price Objective
            bearish_price_objective = self.get_high_of_column_before(measure_column) - result
            return bearish_price_objective
    # existing code...

Please note that you'll need to implement the helper methods find_most_recent_sell_signal, find_most_recent_buy_signal, identify_measure_column, calculate_height, get_low_of_column_before, and get_high_of_column_before as per your data structure and logic.

Then, in your chart rendering method, you can call these methods to calculate the price objectives and add them to your chart.

Please remember that this is a high-level suggestion and you might need to adjust the code according to your specific needs and the existing codebase. Also, don't forget to handle different scaling methods and box sizes as they can affect the calculations. Happy coding!

PnFG commented

@fivethreeo -- At your next opportunity -- Can you please describe enough of the pypnf data structures in your Patterns branch (https://github.com/fivethreeo/pypnf/blob/patterns/pypnf/chart.py) as a basis to implement the helper methods identified in above proto "Price Objective" pseudo-code?

  • find_most_recent_sell_signal
  • find_most_recent_buy_signal
  • identify_measure_column
  • calculate_height
  • get_low_of_column_before
  • get_high_of_column_before

Asking as I don't yet understand the data structures in pypnf codebase well enough to do so myself. Thanks!

# returns colindex of recent buy signal
find_most_recent_buy_signal():
  at_column = np.size(self.signals['type'])

  while at_column > 0:
     signal = self.signals['type']
     if signal = 0: # 0 for buy 1 for sell
       break
    at_columreturn at_column

# returns previous column low for colindex
def prev_column_low(from_colindex)
  if not self.highs_lows_heights_trends:
    self.get_highs_lows_heights_trends()

    highs, lows, heights, trends = self.highs_lows_heights_trends
    if trends[from_colindex] == -1: 
      return lows[from_colindex-2]
    return lows[from_colindex-1]

Not sure my code is the best way to go @swaschke has some functional code with ranking that is not in pypnf

PnFG commented

Appreciate timely inputs, @fivethreeo; it really helps me understand these data structures to return price objectives!

@swaschke: -- at your next opportunity -- I'd appreciate your inputs on functional code w/ ranking and thoughts on which codebase is best to acheive above goals (and also related new issue on returning trend line ) when you can.

FYI: +@Carbonblack8

@swaschke has a private repo at https://github.com/swaschke/pointfig, which has a functional version with counts and ranking, i ported the counts from that in counts branch, ill look into porting the rest aswell, i will also port signals from his functional code

PnFG commented

Awesome, Thanks @fivethreeo!

Started here https://github.com/fivethreeo/pypnf/tree/functional_port , just added the counts again for now

Added the signals and ranking now, need to mull over this code a bit to get a grasp of it

Not sure my code is the best way to go @swaschke has some functional code with ranking that is not in pypnf

the ranking idea is adapted from the book: "Shah (2018) Trading the Markets the Point & Figure way : become a noiseless trader and achieve consistent success in markets. Notion Press, ISBN: 978-1642492248

It is meant to compare different assets and create a "ranking matrix" which is basically an overwiew of assets (i.e. stocks of an index) with their corresponding current rating.

It is well explained in this video

PnFG commented

Appreciate add. Initially I didn't get how Ranking relates to Price Objective logic above.

After watching video -- before reviewing Ranking code -- looks like it already has code for calculate_height above. My takeaway:

  • What: Ranking

  • Why: Momentum proxy to compare or screen stocks

  • How: Using PnF charts, where:

    • score is (number of boxes in last column) * box size
    • if last column is ‘X’ Ranking is 1 * score
    • if last column is ‘O’, Ranking is -1 * score

    Unclear if 'Performance' (Trend proxy) in vid is relevant; both can be used to Screen/Compare different stocks.

Started here https://github.com/fivethreeo/pypnf/tree/functional_port , just added the counts again for now

@fivethreeo Thanks for porting the counts. Based on this I was implementing the counts and tested them against examples from DuPlessis. For horizontal counts with reversal > 1 everything seems to work now. For vertical counts there might be another criterion needed to filter for signals after 'bottoms' based on the rules of DuPlessis. For now there are more horizontal counts identified as in the examples DuPlessis but the counts identified are measured correctly. Horizontal counts for 1-box-reversal charts do not work accurately for now.

You can find the code here

PnFG commented

Appreciate updated code above! I studied latest code plus du Plessis and started my prototype Price Objectives code That led to a few questions for @swaschke -- at your next opportunity -- :

  1. Can you please help document keys of 'counts' dict returned by get_counts() method?

    I started to draft docs for the method and counts dict here - line 2259. I think counts.length is what I need for column height to implement Price Objectives, though need your input.

    Above dict info informs my 1st draft code - e.g., if there's a cleaner or easier way to do so using your Counts branch code. Feedback/Inputs welcome.

  2. One of my test cases hits a bug in reversal > 1 case in counts branch implementation
    It results in "IndexError: index 361 is out of bounds for axis 0 with size 340".
    Please see my repro code for this bug.

  3. One of my test cases generates a different PnF chart than I expect for SPY data.
    Am I passing the correct comparable parameters to PyPnF to do so, or what is the discrepancy?
    Please see my repro code.

FYI: PnF Price Objectives summarizes 3 key methods for Targets/Price Objectives: Breakout and Reversal, Horizontal Counts and Vertical Counts. I'm starting to review & compare it w/ du Plessis and Counts code to inform my next Price Objective prototype.