sammchardy / python-binance

Binance Exchange API python implementation for automated trading
https://python-binance.readthedocs.io/en/latest/
MIT License
6.01k stars 2.2k forks source link

Guidance Requested on Correct PnL Calculation Using Python Binance API #1405

Closed Karlheinzniebuhr closed 6 months ago

Karlheinzniebuhr commented 6 months ago

Hello,

I have questions regarding the correct way to calculate Profit and Loss (PnL) and PnL percentage for futures trading. My approach involves fetching the account balance before and after executing trades, then calculating the PnL based on these values. However, the results I've been getting seem erroneous or misleading.

To fetch the available balance, I use the following method that calls the Binance API:

futures_balances = client.futures_account_balance(asset="BASE_ASSET")
futures_balance_df = pd.DataFrame(futures_balances)
available_balance = round(float(futures_balance_df[futures_balance_df['asset'] == "BASE_ASSET"]['availableBalance'].values[0]), 2)

PnL Calculation Process:

After executing a trade, I calculate the PnL and PnL% with the following logic:

balance_before = # Fetch balance before trade
# Execute trade...
balance_after = # Fetch balance after trade
last_trade_pnl = balance_after - balance_before
pnl_percentage = round((last_trade_pnl / balance_before) * 100, 2)

Is there a more accurate or recommended method to calculate PnL and PnL% considering factors like fees, leverage, and the timing of balance updates? Any guidance or examples you could provide would be greatly appreciated.

Karlheinzniebuhr commented 6 months ago

Solved it with this function. If there is a better way to calculate PnL (ideally a direct API call) please comment below.

def get_last_trade_pnl_and_percentage(self):
    # Fetch the most recent trades for the futures account
    pnl_data = self.client.futures_account_trades(symbol=self.symbol, limit=1)

    # Fetch the current available balance
    futures_balances = self.client.futures_account_balance(asset=self.config.BASE_ASSET)
    futures_balance_df = pd.DataFrame(futures_balances)
    current_balance = round(float(futures_balance_df[futures_balance_df['asset'] == self.config.BASE_ASSET]['availableBalance'].values[0]), 2)

    last_trade_pnl = 0
    last_trade_pnl_percentage = 0

    if pnl_data:
        # Convert the trade data into a DataFrame
        df = pd.DataFrame(pnl_data)

        # Ensure the 'realizedPnl' column is treated as numeric for calculations
        df['realizedPnl'] = pd.to_numeric(df['realizedPnl'])

        if not df.empty:
            # Get the PnL of the last (most recent) trade
            last_trade_pnl = round(df['realizedPnl'].iloc[-1], 2)

            # Calculate the balance before the last trade
            balance_before_last_trade = current_balance - last_trade_pnl

            # Calculate PnL percentage based on the balance before the last trade
            if balance_before_last_trade != 0:
                last_trade_pnl_percentage = round((last_trade_pnl / balance_before_last_trade) * 100, 2)

    # Return both the PnL of the very last trade and its percentage
    return last_trade_pnl, last_trade_pnl_percentage