Optimizing Day Trading with the Money Flow Index Using Python
Written on
Greetings, fellow cryptocurrency enthusiasts and algorithmic trading aficionados! I'm thrilled to present my latest explorations in the realm of day trading strategies. This time, I've ventured into the Money Flow Index (MFI) indicator and I'm eager to share what I've uncovered.
If you enjoyed my earlier article on utilizing the Relative Strength Index (RSI) for day trading, then you're in for a treat. In this piece, I’ll guide you through my methodology for testing MFI strategies, leveraging the capabilities of Python and Binance data.
Disclaimer: I'm not a certified trading advisor, and the insights shared in this article stem from my personal experiences and perspectives. The cryptocurrency market is exceptionally volatile and can change unpredictably, posing a risk of investment loss. Always conduct your own research and consult a professional before making investment decisions. The information provided here should not be interpreted as investment advice; all readers assume responsibility for their own financial choices.
Foundations
I have opted to analyze Binance trading data for the top 20 cryptocurrencies by market capitalization. The data spans the last 100 days with 30-minute candle intervals for computing technical indicators.
For these tests, I will assume that I am investing the same amount for each purchase (let’s say $100).
As we embark on this analytical journey, I assure you that I will maintain the same script structure as in my previous article, while implementing adjustments to enhance the simulation's educational value. The Money Flow Index (MFI) has been chosen as my focal point due to its comprehensive nature—it incorporates both asset price and volume dynamics, providing a broader view of market activity.
The MFI is a pivotal technical analysis tool that evaluates buying and selling pressure by synthesizing price and volume data. This amalgamation offers a nuanced insight into market sentiment and can aid traders in identifying potential trend reversals. In this article, we will delve into the application of the MFI in cryptocurrency day trading, using Python and Binance data to test MFI-driven trading strategies.
I will employ several Python libraries, including python-binance, pandas, pandas-ta, and matplotlib. These libraries are indispensable for traders, offering extensive functionalities for data analysis and visualization.
To set up these libraries, run the following command in your terminal:
pip install python-binance pandas pandas-ta matplotlib
And that's all! Let's dive in!
First Test
In our initial test, we will utilize various MFI values as signals for BUY or SELL actions. This approach allows us to establish specific MFI thresholds as entry or exit points for simulated trades, enabling us to evaluate how varying MFI levels impact the efficacy of our trading strategies.
MFI parameters: mfi_lengths = [20, 30, 40] buy_limits = [50, 60, 70] # BUY SIGNAL if the specified value is exceeded positively sell_limits = [75, 85, 95] # SELL SIGNAL if the specified value is exceeded negatively loss_stop_limits = [15, 20, 25] # SELL SIGNAL if the specified value is exceeded negatively
Python code: import pandas as pd import matplotlib.pyplot as plt import time import pandas_ta as pta from binance.client import Client from pprint import pprint
api_key = "YOUR_BINANCE_API_KEY" api_secret = "YOUR_BINANCE_API_SECRET"
client = Client(api_key, api_secret)
def get_data_frame(symbol='BTCUSDT', period='30m', timeframe='1 hours ago UTC'):
try:
bars = client.get_historical_klines(symbol, period, timeframe)except Exception as e:
print('GET Data error', symbol)
print(e)
time.sleep(5)
bars = client.get_historical_klines(symbol, period, timeframe)
for line in bars:
del line[7:]df = pd.DataFrame(bars, columns=['open_time', 'open', 'high', 'low', 'close', 'volume', 'close_time'])
df['close'] = df['close'].apply(pd.to_numeric)
df['open'] = df['open'].apply(pd.to_numeric)
df['high'] = df['high'].apply(pd.to_numeric)
df['low'] = df['low'].apply(pd.to_numeric)
df['volume'] = df['volume'].apply(pd.to_numeric)
df['close_time'] = df['close_time'].apply(pd.to_numeric) / 1000
return df
top_coins = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'MATICUSDT',
'SOLUSDT', 'DOTUSDT', 'LTCUSDT', 'SHIBUSDT', 'AVAXUSDT', 'DAIUSDT', 'TRXUSDT',
'UNIUSDT', 'ATOMUSDT', 'LINKUSDT', 'ETCUSDT', 'XMRUSDT', 'APTUSDT']
trading_data = {}
# retrieve Binance trade data for coin in top_coins:
trading_data[coin] = get_data_frame(symbol=coin, period='30m', timeframe='100 days ago UTC')
# placeholder variable winner_config = {'profit_ave': False, 'parameters': ''}
# Generate trading Signals mfi_lengths = [20, 30, 40] buy_limits = [50, 60, 70] # BUY SIGNAL if the specified value is exceeded positively sell_limits = [75, 85, 95] # SELL SIGNAL if the specified value is exceeded negatively loss_stop_limits = [15, 20, 25] # SELL SIGNAL if the specified value is exceeded negatively
for length in mfi_lengths:
# adding trading indicator to the trading data set
for coin in top_coins:
trading_data[coin]['mfi'] = pta.mfi(high=trading_data[coin]['high'],
low=trading_data[coin]['low'],
close=trading_data[coin]['close'],
volume=trading_data[coin]['volume'], length=length)
for buy_limit in buy_limits:
for sell_limit in sell_limits:
for loss_stop_limit in loss_stop_limits:
total_profit = []
total_profit_coin_ref = []
for coin in top_coins:
trading_data[coin]['trading_signal'] = '-'
# generate BUY and SELL signals
try:
trading_data[coin].loc[(trading_data[coin]['mfi'] > buy_limit) &
(trading_data[coin]['mfi'].shift() < buy_limit),
'trading_signal'] = 'BUY'
trading_data[coin].loc[((trading_data[coin]['mfi'] < sell_limit) &
(trading_data[coin]['mfi'].shift() > sell_limit)) |
((trading_data[coin]['mfi'] < loss_stop_limit) &
(trading_data[coin]['mfi'].shift() > loss_stop_limit)),'trading_signal'] = 'SELL'
except:
continuepurchase_price = 0
profit_list = []
# run trading simulation across the data set and use trading signals as triggers
for i in range(len(trading_data[coin])):
if trading_data[coin].iloc[i]['trading_signal'] == 'BUY' and purchase_price == 0:
purchase_price = trading_data[coin].iloc[i]['close']if purchase_price != 0:
profit = round(((trading_data[coin].iloc[i]['close'] / purchase_price) * 100) - 100, 2)
# Sell if Profit drops below set limit or trading signal indicates SELL
if trading_data[coin].iloc[i]['trading_signal'] == 'SELL':
profit_list.append(profit)
purchase_price = 0
total_profit.append(round(sum(profit_list), 2))
total_profit_coin_ref.append(f'{coin} {round(sum(profit_list), 2)}%')
if winner_config['profit_ave'] == False:
winner_config['profit_ave'] = round(sum(total_profit) / len(total_profit), 2)
winner_config['parameters'] = f'MFI Parameters: LENGTH: {length}, '
f'BUY: {buy_limit}, SELL: {sell_limit}, '
f'LOSS STOP: {loss_stop_limit}'
elif round(sum(total_profit) / len(total_profit), 2) > winner_config['profit_ave']:
winner_config['profit_ave'] = round(sum(total_profit) / len(total_profit), 2)
winner_config['parameters'] = f'MFI Parameters: LENGTH: {length}, '
f'BUY: {buy_limit}, SELL: {sell_limit}, '
f'LOSS STOP: {loss_stop_limit}'
print(f'Overall Average Profit: {round(sum(total_profit) / len(total_profit), 2)}%, '
f'MFI Parameters: LENGTH: {length}, BUY: {buy_limit}, '
f'SELL: {sell_limit}, LOSS STOP: {loss_stop_limit}, '
f'Details: {total_profit_coin_ref}')
print(f'WINNER! with average profit {winner_config["profit_ave"]}%') print(winner_config['parameters'])
Output:
Truncated output... feel free to run it yourself for more details
Overall Average Profit: 7.77%, MFI Parameters: LENGTH: 40, BUY: 70, SELL: 85, LOSS STOP: 20, Details: ['BTCUSDT 0%', 'ETHUSDT 0%', 'BNBUSDT -25.7%', ...]
Second Test
For our next test, we’ll introduce a fixed stop loss at a 5% loss (forced sell). A stop loss is a crucial aspect of any trading strategy, as it helps minimize potential losses and safeguard your capital. By implementing a fixed stop loss, we can ensure that trades are automatically closed if they reach a certain loss threshold, thereby reducing the risk of substantial financial damage.
MFI parameters: mfi_lengths = [20, 30, 40] buy_limits = [50, 60, 70] # BUY SIGNAL if the specified value is exceeded positively sell_limits = [75, 85, 95] # SELL SIGNAL if the specified value is exceeded negatively loss_stop_limits = [15, 20, 25] # SELL SIGNAL if the specified value is exceeded negatively loss_stop_in_percent = -5
Python code: # The Python code for this test remains largely similar to the first test. # Adjustments will be made to incorporate the fixed stop loss.
Output:
Truncated output... feel free to run it yourself for more details
Overall Average Profit: 13.87%, MFI Parameters: LENGTH: 40, BUY: 70, SELL: 85, LOSS STOP: 20, Details: ['BTCUSDT -5%', 'ETHUSDT -10%', ...]
Final Test
In our concluding test, we will focus on refining the winning parameters to identify an optimal configuration for maximizing profits. This will involve analyzing the most successful strategies from previous tests and making minor adjustments to see if we can further enhance their effectiveness.
MFI parameters: mfi_lengths = [27, 30, 33] buy_limits = [45, 50, 55] # BUY SIGNAL if the specified value is exceeded positively sell_limits = [90, 95, 99] # SELL SIGNAL if the specified value is exceeded negatively loss_stop_limits = [23, 25, 27] # SELL SIGNAL if the specified value is exceeded negatively loss_stop_in_percent = -5
Python code: # The Python code for this test remains similar, focusing on the optimized parameters.
Output:
WINNER! with average profit: 36.92% MFI Parameters: LENGTH: 30, BUY: 50, SELL: 95, LOSS STOP: 25 Loss Stop Profit Drop: -5%