Market Profile using Python!

If anyone did a technical analysis using popular trading charts, would have noticed Market Profile as one of the techniques. This was a really different way of looking at the time series data.

The logic is slice the data for a period, say every ’30 min’ and assign an alphabet, starting with ‘A’ to all the ‘Price’. Price is also rounded of so that we don’t have too many keys based on Price. Simply put in programming parlance create a dictionary with Price(rounded of) as keys and add new Alphabet for every slice.

Say first 30 min, the low is 100 and high is 110, then starting with 100 to 110, append ‘A’ as a value. so our dictionary would be

[{100, ‘A’},{101, ‘A’},{102, ‘A’},{103, ‘A’} ..{110,’A’}],

then, next  slice of 30 min, the price drops to low of 105 and high of 112, the dictionary would be

[{100, ‘A’}..{104, ‘A’},{105, ‘AB’},{106, ‘AB’},{107, ‘AB’} ..{110, ‘AB’},{111, ‘A’},{112,’B’}]

For a typical day, a stock traded of high of 282 and a low of 272, sliced 30 min,  would look like this

[(282, 'E'),
 (281, 'EFK'),
 (280, 'DEFIJK'),
 (279, 'DEFGIJKL'),
 (278, 'CDEFGHIKLM'),
 (277, 'CDGHLM'),
 (276, 'ABCGHM'),
 (275, 'ABCGM'),
 (274, 'ABCMN'),
 (273, 'AB'),
 (272, 'B')]

So, we can infer, the stock opened at  276 , ‘A’ then in next 30 min, moved  low to 272 ‘B’, moved high next 1 hour 282, ‘E’, finally closed at 274, ‘N’

Here comes the code!

That’s about the Market Profile but how to use Python. There is a nice function(s) to group the data using time(frequency), the function returns a set of groups , by the period 30 min.

df.groupby and pd.Grouper

here is how to create a group with a time slice of 30 min
TGroups=df.groupby([pd.Grouper(key='DateTime', freq='30Min')])
DateTime‘, is the column in the dataset that has timestamp of each trade/tick. Now iterate through the groups and make a dictionary for each group(slice), taking the high and low for the each group.

Here is the complete code


def Market_Profile_G(df, frequency='30Min', debug=0):   
   #intialize dictionary and char 'A, B, C..'    
   md=defaultdict(str)
   char_a=64
   #make a group based on Timestamp with frequency 30min
TGroups=df.groupby([pd.Grouper(key='DateTime', freq=frequency)])

 

   #iterate over each group and add to dictionary, 
   #dictionary keys are 'High' and 'Low' of each group, rounded and values are 
   #char A, B incremented for each period(freq group), default 30 min 
   #since we grouped based on freq, for each group increment the char i.e +1

 

   for t,g in TGroups:
       char_a +=1     
       #skip non alphabets
       if char_a == 91:
          char_a=97
       min_price=np.round(g.Low.min())
       max_price=np.round(g.High.max())
       if debug==1:
          print(g.Low.min(), g.High.max()) 
       for price in  range(int(min_price), int(max_price+1)):
          md[price]+=(chr(char_a))
   return sorted(md.items(), key=lambda k:k,reverse=1)

def Market_Profile_G(df, frequency=’30Min’, debug=0):  This function takes a DataFrame, with columns df=data[[‘DateTime’, ‘Open’, ‘High’, ‘Low’, ‘Close’, ‘Volume’,]] and returns a dictionary {price, string}.

When you print this is what you see

[(282, 'E'),
 (281, 'EFK'),
 (280, 'DEFIJK'),
 (279, 'DEFGIJKL'),
 (278, 'CDEFGHIKLM'),
 (277, 'CDGHLM'),
 (276, 'ABCGHM'),
 (275, 'ABCGM'),
 (274, 'ABCMN'),
 (273, 'AB'),
 (272, 'B')]

PS: The Alphabets are appended to all the prices between High and Low, sometimes, a trade may not have happened at a particular price, so, Alphabets may be added based on actual price within a group.