JPStrydom / Crypto-Trading-Bot

Automated Bittrex crypto-currency technical analysis and trading tool
MIT License
301 stars 102 forks source link

Feature: MACD implementation #14

Open MaxCCC opened 6 years ago

MaxCCC commented 6 years ago

Is there a chance we can trigger our auto-buys/auto-sells with a MACD (Moving Average Convergence Divergence) indicator in the feature?

JPStrydom commented 6 years ago

Would be interesting to see some more signals. Adding the trigger should be easy once the MACD has been implemented. Feel free to look into adding the signal yourself - have a look at the calculate_RSI method inside the trader.py file (line 343 currently). If you add a calculate_MACD method there, I can help you add it to the buy strategy.

lvthillo commented 6 years ago

@MaxCCC @JPStrydom It seems it should not be too difficult when I look here. Using stockstats and/or panda it should be relatively easy to calculate macd. Maybe the difficulty could be getting the right data? I'm not in the codebase (yet) + have to look which data the bittrex API can provide.

lvthillo commented 6 years ago

To implement this we'll probably need APIv2 instead of 1.1 of Bittrex: https://bittrex.com/Api/v2.0/pub/market/GetTicks?marketName=BTC-WAVES&tickInterval=thirtyMin&_=1499127220008 I don't know if it's an option for you @JPStrydom (not sure if it's official)

JPStrydom commented 6 years ago

I'm already using some of the V2 endpoints in the bot. I use one for the RSI. Have a look at the code I mentioned, and you'll see how to use it.

lvthillo commented 6 years ago

@JPStrydom I looked a bit in the code. First of all, I'm not a python dev as you probably will see. I checked the historical_data which I need to calculate the macd. So I used this part int the code (inget_closing_prices in trader.py)

historical_data = self.Bittrex.get_historical_data(coin_pair, period, unit)

I replaced it with (This is not a real implementation but it looked the best way to me to test it):

historical_data = self.Bittrex.get_historical_data(coin_pair, period, unit)
self.calculate_MACD(historical_data)
exit()

_PS. I'm not sur why this seems not to work: historical_data = self.Bittrex.get_historical_data('BTC-LTC', 'day', 100) Or even not the same values as the defauls: un_historical_data = self.Bittrex.get_historical_data('BTC-LTC', 'fiveMin', 42) _

But okay I just get the historical data and trigger calculate_MACD. Historical data looks like this: [{'O': 0.016291, 'H': 0.016291, 'L': 0.01625555, 'C': 0.01627328, 'V': 148.4653244, 'T': '2018-05-02T14:45:00', 'BV': 2.41433593}, ...

Where O is open, H is high, L is low, C is close, V is volume, T is datetime, BV is Base volume. I found the stockstats. It seems to expect: open, high, low, close, volume (like here).

import pandas as pd
from stockstats import StockDataFrame

    def calculate_MACD(self, historical_data):
        df = pd.io.json.json_normalize(historical_data)
        # Get logical order and ignore unnecessary BV
        df = df[['T', 'L', 'H', 'O', 'C']]
        df.columns = ['datetime', 'low', 'high', 'open', 'close']
        df = StockDataFrame.retype(df)
        df['macd'] = df.get('macd')
        print(df)

Is this something you could use? I did not verify the data yet. Maybe I can create a drawing to check if it's the same as bittrex is providing.

OUTPUT:

               datetime       low      high      open     close  close_12_ema  \
0   2018-05-02T14:50:00  0.016260  0.016291  0.016260  0.016291      0.016291   
1   2018-05-02T14:55:00  0.016290  0.016291  0.016291  0.016291      0.016291   
2   2018-05-02T15:00:00  0.016274  0.016291  0.016291  0.016274      0.016284   
3   2018-05-02T15:05:00  0.016270  0.016291  0.016274  0.016274      0.016281   
4   2018-05-02T15:10:00  0.016271  0.016291  0.016291  0.016271      0.016278   
5   2018-05-02T15:15:00  0.016260  0.016271  0.016270  0.016271      0.016276   
6   2018-05-02T15:20:00  0.016270  0.016271  0.016271  0.016271      0.016275   
7   2018-05-02T15:25:00  0.016256  0.016271  0.016271  0.016271      0.016274   
8   2018-05-02T15:30:00  0.016257  0.016291  0.016271  0.016291      0.016278   
9   2018-05-02T15:35:00  0.016291  0.016314  0.016291  0.016291      0.016280   
10  2018-05-02T15:40:00  0.016291  0.016314  0.016314  0.016300      0.016284   
11  2018-05-02T15:45:00  0.016300  0.016320  0.016313  0.016316      0.016290   
12  2018-05-02T15:50:00  0.016300  0.016322  0.016320  0.016322      0.016295   
13  2018-05-02T15:55:00  0.016300  0.016322  0.016300  0.016319      0.016299   
14  2018-05-02T16:00:00  0.016300  0.016322  0.016319  0.016322      0.016303   
15  2018-05-02T16:05:00  0.016270  0.016322  0.016322  0.016300      0.016303   
16  2018-05-02T16:10:00  0.016270  0.016322  0.016300  0.016270      0.016297   
17  2018-05-02T16:15:00  0.016270  0.016290  0.016290  0.016270      0.016293   
18  2018-05-02T16:20:00  0.016270  0.016322  0.016270  0.016300      0.016294   
19  2018-05-02T16:25:00  0.016280  0.016322  0.016280  0.016322      0.016298   
20  2018-05-02T16:30:00  0.016290  0.016351  0.016322  0.016290      0.016297   
21  2018-05-02T16:35:00  0.016270  0.016350  0.016290  0.016350      0.016305   
22  2018-05-02T16:40:00  0.016270  0.016350  0.016322  0.016316      0.016307   
23  2018-05-02T16:45:00  0.016267  0.016350  0.016316  0.016283      0.016303   
24  2018-05-02T16:50:00  0.016256  0.016350  0.016299  0.016260      0.016297   
25  2018-05-02T16:55:00  0.016256  0.016350  0.016280  0.016295      0.016296   
26  2018-05-02T17:00:00  0.016255  0.016365  0.016350  0.016256      0.016290   
27  2018-05-02T17:05:00  0.016255  0.016357  0.016260  0.016257      0.016285   
28  2018-05-02T17:10:00  0.016138  0.016356  0.016257  0.016327      0.016291   
29  2018-05-02T17:15:00  0.016250  0.016325  0.016300  0.016270      0.016288   
30  2018-05-02T17:20:00  0.016270  0.016325  0.016270  0.016294      0.016289   
31  2018-05-02T17:25:00  0.016240  0.016294  0.016280  0.016275      0.016287   
32  2018-05-02T17:30:00  0.016250  0.016310  0.016275  0.016310      0.016290   
33  2018-05-02T17:35:00  0.016294  0.016325  0.016310  0.016325      0.016296   
34  2018-05-02T17:40:00  0.016295  0.016325  0.016325  0.016325      0.016300   
35  2018-05-02T17:45:00  0.016320  0.016358  0.016325  0.016358      0.016309   
36  2018-05-02T17:50:00  0.016328  0.016358  0.016328  0.016342      0.016314   
37  2018-05-02T17:55:00  0.016320  0.016358  0.016358  0.016350      0.016320   
38  2018-05-02T18:00:00  0.016304  0.016358  0.016350  0.016342      0.016323   
39  2018-05-02T18:05:00  0.016295  0.016358  0.016342  0.016325      0.016323   
40  2018-05-02T18:10:00  0.016320  0.016325  0.016325  0.016320      0.016323   
41  2018-05-02T18:15:00  0.016320  0.016350  0.016320  0.016325      0.016323   

    close_26_ema          macd         macds         macdh  
0       0.016291  0.000000e+00  0.000000e+00  0.000000e+00  
1       0.016291  0.000000e+00  0.000000e+00  0.000000e+00  
2       0.016285 -5.364720e-07 -2.198656e-07 -6.332128e-07  
3       0.016282 -7.673224e-07 -4.053184e-07 -7.240079e-07  
4       0.016279 -9.840482e-07 -5.774774e-07 -8.131415e-07  
5       0.016278 -1.095833e-06 -7.179806e-07 -7.557047e-07  
6       0.016276 -1.148646e-06 -8.269706e-07 -6.433513e-07  
7       0.016276 -1.175578e-06 -9.107475e-07 -5.296611e-07  
8       0.016278 -1.736492e-07 -7.404742e-07  1.133650e-06  
9       0.016280  5.396186e-07 -4.536591e-07  1.986555e-06  
10      0.016282  1.526417e-06 -2.042976e-08  3.093693e-06  
11      0.016286  3.128891e-06  6.559122e-07  4.945957e-06  
12      0.016291  4.593851e-06  1.489317e-06  6.209068e-06  
13      0.016294  5.477145e-06  2.323573e-06  6.307143e-06  
14      0.016297  6.230060e-06  3.133363e-06  6.193394e-06  
15      0.016297  5.388769e-06  3.597508e-06  3.582521e-06  
16      0.016294  2.824995e-06  3.439446e-06 -1.228904e-06  
17      0.016292  8.256166e-07  2.907090e-06 -4.162947e-06  
18      0.016293  1.203498e-06  2.561390e-06 -2.715784e-06  
19      0.016296  2.907763e-06  2.631472e-06  5.525815e-07  
20      0.016295  2.079193e-06  2.519988e-06 -8.815903e-07  
21      0.016300  5.436837e-06  3.107695e-06  4.658285e-06  
22      0.016301  5.687564e-06  3.626732e-06  4.121664e-06  
23      0.016300  3.550644e-06  3.611442e-06 -1.215975e-07  
24      0.016296  2.234972e-07  2.931284e-06 -5.415573e-06  
25      0.016296  9.827136e-08  2.362964e-06 -4.529385e-06  
26      0.016293 -2.806667e-06  1.326532e-06 -8.266398e-06  
27      0.016290 -4.934626e-06  7.187325e-08 -1.001300e-05  
28      0.016293 -1.516713e-06 -2.463365e-07 -2.540754e-06  
29      0.016291 -2.946092e-06 -7.869569e-07 -4.318271e-06  
30      0.016291 -2.243066e-06 -1.078467e-06 -2.329197e-06  
31      0.016290 -3.088491e-06 -1.480791e-06 -3.215400e-06  
32      0.016292 -1.129961e-06 -1.410580e-06  5.612388e-07  
33      0.016294  1.523832e-06 -8.234002e-07  4.694464e-06  
34      0.016297  3.581661e-06  5.796961e-08  7.047384e-06  
35      0.016302  7.647501e-06  1.576369e-06  1.214226e-05  
36      0.016305  9.523706e-06  3.166249e-06  1.271491e-05  
37      0.016308  1.148908e-05  4.831160e-06  1.331583e-05  
38      0.016311  1.228623e-05  6.322422e-06  1.192762e-05  
39      0.016312  1.146973e-05  7.352020e-06  8.235417e-06  
40      0.016313  1.032424e-05  7.946527e-06  4.755419e-06  
41      0.016314  9.684967e-06  8.294244e-06  2.781445e-06  

Process finished with exit code 0
JPStrydom commented 6 years ago

Looking good dude 👍 I'm not entirely sure how to use the MACD for triggers, but if the function gives it in a easy to read format, it can easily be added as a buy/sell trigger.

How would one interpret the MACD output?

lvthillo commented 6 years ago

@JPStrydom Well I have to admit I need to investigate it more (also know someone who knows it well). I'm more familiar with the charts and comparing the macd and signal line instead of looking to the real data. But what I found here:

(I'm still checking every 5minutes while I think it needs to be a day, but that's stuff I need to explore more)

 def calculate_MACD(self, historical_data):
        df = pd.io.json.json_normalize(historical_data)
        df = df[['T', 'L', 'H', 'O', 'C']]
        #ignore BV
        df.columns = ['datetime', 'low', 'high', 'open', 'close']
        df = StockDataFrame.retype(df)
        df['macd'] = df.get('macd')
        #print(df)
        signal = df['macds']
        macd = df['macd']

        listLongShort = ["No data"]

        for i in range(1, len(signal)):
            #                          # If the MACD crosses the signal line upward
            if macd[i] > signal[i] and macd[i - 1] <= signal[i - 1]:
                listLongShort.append("BUY")
            #                          # The other way around
            elif macd[i] < signal[i] and macd[i - 1] >= signal[i - 1]:
                listLongShort.append("SELL")
            #                          # Do nothing if not crossed
            else:
                listLongShort.append("HOLD")

        df['Advice'] = listLongShort

        # The advice column means "Buy/Sell/Hold" at the end of this day or
        #  at the beginning of the next day, since the market will be closed

        print(df['Advice'])

Output:

Tracking 192 Bittrex Markets

0     No data
1         BUY
2        SELL
3        HOLD
4        HOLD
5        HOLD
6         BUY
7        HOLD
8        HOLD
9        HOLD
10       HOLD
11       SELL
12       HOLD
13       HOLD
14       HOLD
15       HOLD
16       HOLD
17       HOLD
18       HOLD
19        BUY
20       HOLD
21       HOLD
22       HOLD
23       HOLD
24       HOLD
25       HOLD
26       HOLD
27       HOLD
28       HOLD
29       HOLD
30       HOLD
31       HOLD
32       HOLD
33       SELL
34       HOLD
35       HOLD
36       HOLD
37        BUY
38       SELL
39       HOLD
40        BUY
41       HOLD
lvthillo commented 6 years ago

I went a bit more in depth and macd and RSI are often combined. The unit (5 minutes in the example) can be used for macd too. It's just a choice like with RSI. It can also be one day.

I think it needs some further research. A blind implementation won't be useful. I don't know if I have the time/knowledge to try to implement some "test" scenario without buying/selling in reality. I'm convinced they can be useful when they are combined but it's a "search" to find out good values for RSI (30/70, 25/75, 20/80) + 14 period (or 7, 9 or, 10) which are also used in 'short term' trading) etc...

lvthillo commented 6 years ago

I'm adding some test scenario with what I've posted above. I'm using a thickinterval of 30 mins but as I've mentioned it can be everything. I'm not sure about the period (to get the historical data). Now I chose for 100 because I saw it as max period in crypto-signal .. It can be as much as I want. I'm using the value of RSI for my 30 mins and I use the last value of my df list.

dfprinted (last line): 99 2018-05-04T19:00:00 0.016947 0.016947 0.016947 0.016947 0.016853 So it's 7PM at (bittrex API time, I checked it). When I translate it to my time it corresponds with the latest ThickInterval.

Get the list:

0     No data
1        SELL
2        HOLD
3         BUY
4        HOLD
5        HOLD
6        HOLD
7        HOLD
8        HOLD
9        HOLD
10       HOLD
11       HOLD
12       HOLD
13       HOLD
14       HOLD
15       HOLD
16       HOLD
17       SELL
18        BUY
19       HOLD
20       HOLD
21       HOLD
22       HOLD
23       HOLD
24       SELL
25       HOLD
26       HOLD
27       HOLD
28       HOLD
29       HOLD
       ...   
70       HOLD
71       HOLD
72       HOLD
73        BUY
74       HOLD
75       HOLD
76       HOLD
77       HOLD
78       HOLD
79       HOLD
80       HOLD
81       HOLD
82       HOLD
83       HOLD
84       HOLD
85       HOLD
86       HOLD
87       HOLD
88       HOLD
89       HOLD
90       HOLD
91       SELL
92       HOLD
93       HOLD
94       HOLD
95        BUY
96       HOLD
97       HOLD
98       HOLD
99       HOLD

and I pick the last value which is HOLD in this case (most cases). Now it would be cool to adapt the other functions to use RSI and macd. If you're still interested we could maybe implement this in a side branch and use it as test before implementing it? My knowledge does not extend far enough now to adjust everything (changing parameter stuff, buy / sell function etc). Otherwise I'll stop spamming you and maybe try some stuff on my own :)

JPStrydom commented 6 years ago

I like the idea of only applying the RSI check to MACD buy signals. It'll make the trades more secure.

Once I have some time I'll make a new branch and add this functionality to it.

I'll add it to buy first and then later to sell.

I'll use your functionality for the MACD and I'll let you know when it's up.

Thanks for all the work! 👍

yellowgoatbot commented 5 years ago

Has the MACD check been integrated into the rest of the source code? I can't find any recent commits