Getting the Final Trade Log of Entropy Alpha Strategy with Entry and Exit

In the previous lesson, we generated a raw trade log from the Entropy Alpha scanner. Our next objective is to process this log to simulate the trades based on our strategy rules and calculate the final profit and loss (P/L) for each trade. This involves determining the exit point for each trade and then calculating the outcome in terms of points and net P/L in Rupees.

Note. This lesson is the second part of a series. Click here to read the first part where we generate the initial trigger log.

Step 6: Simulating the Trade Exits

The first task is to simulate the outcome of each trade trigger. We will iterate through our trade log and determine the exit time and price for each entry. The exit is determined by one of two conditions: the price hitting the day’s high (our target) or an end-of-day (EOD) square-off at 2:50 PM if the target is not met.

We will add three new columns to our DataFrame:

  • square_off_time: The timestamp when the trade was exited. This is either the time the target was hit or 2:50 PM for an EOD exit.
  • square_off_price: The price at which the trade was exited. If the target is hit, this is the day’s high. Otherwise, it is the closing price at 2:50 PM.
  • is_target: A boolean flag (True/False) indicating whether the trade successfully hit its target.

After simulation, the DataFrame will look like this:

				Triggered at	stocks	Trigger Date	Trigger Time	price	high	square_off_time	square_off_price	is_target
59	2023-04-03 10:01:00	MARUTI	2023-04-03	10:01:00	8558.15	8634.85	2023-04-03 14:50:00+05:30	8554.20	False
57	2023-04-03 10:04:00	M&M	2023-04-03	10:04:00	1178.5	1187.15	2023-04-03 10:22:00+05:30	1187.15	True
54	2023-04-03 10:10:00	ASHOKLEY	2023-04-03	10:10:00	142.6	143.30	2023-04-03 14:50:00+05:30	141.60	False
53	2023-04-03 10:16:00	CHAMBLFERT	2023-04-03	10:16:00	270.65	273.90	2023-04-03 15:19:00+05:30	273.90	True
51	2023-04-03 10:17:00	GMRINFRA	2023-04-03	10:17:00	42.8	43.95	2023-04-03 14:04:00+05:30	43.95	True
...	...	...	...	...	...
4	2023-04-20 12:49:00	CUB	2023-04-20	12:49:00	132.7	134.35	2023-04-20 14:50:00+05:30	133.25	False
3	2023-04-20 14:16:00	BAJAJ-AUTO	2023-04-20	14:16:00	4321	4336.60	2023-04-20 14:50:00+05:30	4317.85	False
2	2023-04-20 15:21:00	TATACONSUM	2023-04-20	15:21:00	705.7	706.50	2023-04-20 14:50:00+05:30	705.00	False
1	2023-04-21 09:58:00	ASIANPAINT	2023-04-21	09:58:00	2854.75	2888.00	2023-04-21 14:23:00+05:30	2888.00	True
0	2023-04-21 10:07:00	APOLLOTYRE	2023-04-21	10:07:00	335.5	337.85	2023-04-21 14:50:00+05:30	334.05	False
60 rows × 9 columns

Step 7: Adding Lot Sizes and Normalizing Data

To calculate the final P/L in Rupees, we need the lot size for each futures contract. Lot sizes vary for each instrument in the F&O segment. We can retrieve this information from the master instrument list provided by the KiteConnect API.

The following function looks up the lot size for a given trading symbol. We assume the full instrument list is loaded into a DataFrame named `instrumentList`.

def get_lotsize(tradesymbol,exchange="NFO"):
    if(exchange=="NSE"):
        if(tradesymbol=="NIFTY"):tradesymbol="NIFTY 50"
        if(tradesymbol=="BANKNIFTY"):tradesymbol="NIFTY BANK"
    #print(tradesymbol)
    #print(exchange)
    dataToken = instrumentList[(instrumentList['tradingsymbol'] == tradesymbol)&(instrumentList['exchange']==exchange)]
    return dataToken.lot_size.iloc[0]

df["lotsize"] = df["stocks"].apply(lambda x: get_lotsize(x+"23APRFUT"))

Next, a minor data cleaning step is required. The square_off_time column includes timezone information (e.g., “+05:30”), while Triggered at does not. We will remove the timezone to make the timestamp format uniform across the DataFrame.

import datetime
df['square_off_time'] = df['square_off_time'].apply(lambda x: datetime.datetime.strptime(str(x)[:-6], '%Y-%m-%d %H:%M:%S'))
Pitfall. The code hardcodes the futures expiry month and year (23APRFUT). For a robust backtesting engine, this should be dynamically generated based on the trade date to ensure the correct contract is always used.

Step 8: Calculating Profit and Loss

With all the necessary data in place, we can now calculate the final P/L. This involves four steps:

  1. Remove the redundant Trigger Date and Trigger Time columns.
  2. Rename the price column to entry_price for better clarity.
  3. Calculate the profit or loss in points: pl_points = square_off_price - entry_price.
  4. Calculate the net P/L in Rupees: pl = pl_points * lotsize.

The corresponding Python code is as follows:

# remove "Trigger Date" column
df = df.drop("Trigger Date", axis=1)
# remove "Trigger Time" column
df = df.drop("Trigger Time", axis=1)
# rename "price" column to "entry_price"
df = df.rename(columns={"price": "entry_price"})
df["pl_points"] = df["square_off_price"]-df["entry_price"]
df["pl"] = df["pl_points"]*df["lotsize"]
df

The Final Trade Log

After executing these steps, we have our final trade log. This comprehensive table shows each trade’s entry and exit details, along with the resulting profit or loss.

	Triggered at	stocks	entry_price	high	square_off_time	square_off_price	is_target	lotsize	pl_points	pl
59	2023-04-03 10:01:00	MARUTI	8558.15	8634.85	2023-04-03 14:50:00	8554.20	False	100	-3.95	-395.0
57	2023-04-03 10:04:00	M&M	1178.5	1187.15	2023-04-03 10:22:00	1187.15	True	700	8.65	6055.0
54	2023-04-03 10:10:00	ASHOKLEY	142.6	143.30	2023-04-03 14:50:00	141.60	False	5000	-1.0	-5000.0
53	2023-04-03 10:16:00	CHAMBLFERT	270.65	273.90	2023-04-03 15:19:00	273.90	True	1500	3.25	4875.0
51	2023-04-03 10:17:00	GMRINFRA	42.8	43.95	2023-04-03 14:04:00	43.95	True	22500	1.15	25875.0
...	...	...	...	...	...	...	...	...	...	...
5	2023-04-20 10:02:00	ICICIBANK	897.05	901.00	2023-04-21 09:32:00	901.00	True	700	3.95	2765.0
4	2023-04-20 12:49:00	CUB	132.7	134.35	2023-04-20 14:50:00	133.25	False	5000	0.55	2750.0
3	2023-04-20 14:16:00	BAJAJ-AUTO	4321	4336.60	2023-04-20 14:50:00	4317.85	False	250	-3.15	-787.5
2	2023-04-20 15:21:00	TATACONSUM	705.7	706.50	2023-04-20 14:50:00	705.00	False	900	-0.7	-630.0
1	2023-04-21 09:58:00	ASIANPAINT	2854.75	2888.00	2023-04-21 14:23:00	2888.00	True	200	33.25	6650.0
0	2023-04-21 10:07:00	APOLLOTYRE	335.5	337.85	2023-04-21 14:50:00	334.05	False	3500	-1.45	-5075.0

Interpretation of the Trade Log

The final DataFrame is the cornerstone for performance analysis.

  • The is_target column quickly tells us if a trade was a winner (True) or if it was closed at EOD, which could be a smaller profit or a loss (False).
  • The pl_points column shows the gross profit or loss in terms of price movement, independent of position size.
  • The pl column provides the final net profit or loss in Rupees for a single lot trade, which is the most critical metric for evaluating the strategy’s real-world performance.
Intuition. This final trade log is the raw material for all further analysis. From this data, we can calculate key performance indicators (KPIs) like Win Rate, Profit Factor, and Maximum Drawdown to objectively assess the strategy’s effectiveness. We will cover this in the next lesson.
Post a comment

Leave a Comment

Your email address will not be published. Required fields are marked *

×Close