MerlinR / Hexital

Hexital - Incremental Technical Analysis Library
MIT License
12 stars 2 forks source link

Introduce easier way to use movement methods. #17

Open MerlinR opened 5 months ago

MerlinR commented 5 months ago

Prior to 1.1.0 the Movement patterns where partially implemented within the Hexital/Indicator class's, the purpose was to make it very easy to call/use them, E.G: we could easily call the "above" movement method for two indicators as follows.

strategy = Hexital("Test strategy", candles, [EMA(), SMA()])
strategy.calculate()
strategy.above("EMA_10", "SMA_10") 

However this was removed in 1.1.0 due to the fact everytime a new movement/pattern was added the Hexital and Indicator class would need to implement the method as well, this would quickly become a hassle and extremely messy. However now to do the same movement call is as follows:

from hexital.analysis import movement
strategy = Hexital("Test strategy", candles, [EMA(), SMA()])
strategy.calculate()
movement.above(strategy.candles(), "EMA_10", "SMA_10") 

or worse with timeframes:

from hexital.analysis import movement
strategy = Hexital("Test strategy", candles, [EMA(timeframe="T5"), SMA(timeframe="T5")])
strategy.calculate()
movement.above(strategy.candles("T5"), "EMA_10_T5", "SMA_10_T5") 

A new approach is needed to find some middle ground between the two. The user simplicity of it existing within Hexital/Indicator and the maintainability of it being external.

MerlinR commented 5 months ago

Possible options:

1: Using Python's getattr to hack Movements/patterns into Hexital/Indicator. Essentially Having them check if a pattern or movement named the given indicator exist and then calling them. This is fairly hacky and wont support typing or IDE type hinting, could also be a pain to debug.

strategy = Hexital("Test strategy", candles, [EMA(), SMA()])
strategy.calculate()
strategy.above("EMA_10", "SMA_10") 

2: Update Movement/Patterns argument to accept List[Candles] | Indicator | Hexital. Where it can call the previous method _verify_indicators to find and verify the List[Candles] for the given indicators.

from hexital.analysis import movement
strategy = Hexital("Test strategy", candles, [EMA(timeframe="T5"), SMA(timeframe="T5")])
strategy.calculate()
movement.above(strategy, "EMA_10_T5", "SMA_10_T5") 

3:?

MerlinR commented 1 week ago
  1. Not doing this hacky nonsense.
  2. This in my mind is still the ideal solution, the issue is ciruclar imports due to movement methods being used in indicators, so if method in movement imports Indicator/Hexital for typing to get the candles this becomes circular.
  3. I have updated Hexital method candles to allow getting the correct candles list giving the timeframe or indicator name, making it easier to get the right candle's to pass:
    from hexital.analysis import movement
    strategy = Hexital("Test strategy", candles, [EMA(timeframe="T5"), SMA(timeframe="T5")])
    strategy.calculate()
    movement.above(strategy.candles("EMA_10_T5"), "EMA_10_T5", "SMA_10_T5") 
    ...
    movement.above(strategy.candles("T5"), "EMA_10_T5", "SMA_10_T5") 
MerlinR commented 3 days ago

Re-opening as come to a solution that works for me, I have shuffled some the methods and util functions created to allow movement methods to be given either List[Candle], Indicator or Hexital this means it alot cleaner and easier to call movement methods, it does mean you cannot use the same movement methods within an indicator, however they can still use the analysis util methods.

This means they will auto search and pick up the correct set of Candle's based on the given indicator name given, automatically.

Another key point is this method will allow being able to run movement's methods over multiple timeframes. For instance does my 1 minute 14 EMA cross over my 1H EMA, which before was not possible, without setting a 1 minute EMA with a high period.

The caveat with achieving this while being able to select an Candle Index will be to heavily run on the Candle timestamp's. For example, if I want to check if 1 min 14 EMA crosses my 5 min EMA, with index -2. It will get the prev 1 minute EMA indicator reading, look at it's timestamp and find the latest Candle in the 5 minute EMA that would include it, and compare those two Candles. This ensure's we can use Index over multiple timeframes and ensure it's comparing the correct readings.