0

If I give the code an 'original' value to work from I want each x-tick to show the percentage change from that value.

I.E if I set 10 as the original value I want the grid line at 5 to read like 5(-50%) and 20 as 20(+100%).

Colours for the term in brackets would be an added bonus.

Edit: Source code

So here is the code. It has been changed a number of times to fill a certain role so it's not the best but you get the idea. It's just a p/l calculator for trading that takes into account commissions and dividend payments.

I'd like the center of the graph to be "current stock price" and the stock prices either side of that on the graph to show percentage changes from the 'current stock price'

from colorama import Fore, Style
import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.widgets import Cursor


name='XYZ'
current_stock_price=8.66

closing_price=current_stock_price       #price at which you close the position

#first trade 
entrance_price1=9.55
number_shares1=1500
dividend1=0.0
longshort1='short'   #is it a long or short position? 

#second trade 
entrance_price2=8.93
number_shares2=1200
dividend2=0.0
longshort2='short' 

def commission_stock(commission_rate, cost, commission_minimum,     number_shares): 

    com=commission_rate/100*cost
    #com=commission_rate*number_shares

    if com<commission_minimum:
        com=commission_minimum

    return com 

def pl_calculator(entrance_price, closing_price, number_shares, \
              commission_shares, commission_minimum, dividend_amount, name,\
              longshort): 

    name=name
    longshort=longshort

    entrance_price= entrance_price
    closing_price= closing_price

    stock_change=closing_price-entrance_price #change in stock price

    number_shares=number_shares

    commission_shares=commission_shares#percent or per/number of shares
    commission_minimum=commission_minimum

    dividend_amount=dividend_amount   #dollars per share 
    dividend_cost=dividend_amount*number_shares #how much you pay in dividends

    margin_req=1

    nominal_value=number_shares*entrance_price #value of shares (not   necessarily   how much we own if margin is involved) 
    cost_to_exit_share=number_shares*closing_price

    outlay=nominal_value*margin_req #amount of money required up front 

    movement=float(closing_price)/entrance_price*100-100 #stock price movement

    stock_pl=number_shares*(closing_price-entrance_price) #numerical value of profit or loss 

    commission_shares_enter=commission_stock(commission_shares, nominal_value, commission_minimum, number_shares)
    commission_shares_exit=commission_stock(commission_shares, cost_to_exit_share,    commission_minimum, number_shares)
    commission=commission_shares_enter+commission_shares_exit

    if longshort=='long':
        stock_pl=stock_pl-commission_shares_enter-      commission_shares_exit+dividend_cost
    elif longshort=='short': 
        stock_pl=-stock_pl-commission_shares_enter-commission_shares_exit-dividend_cost
    else: 
        raise AttributeError 

    pl_perc=stock_pl/nominal_value*100 
    pl_perc_outlay=stock_pl/outlay*100 #profit or loss on outlaid cash. If margin=1 then pl_perc_outlay=pl_perc

    return [stock_pl, pl_perc, commission, dividend_cost]


def print_graph(current_stock_price, profit_current, profit_chosen, closing_price, name):

#creates a list of stock prices either side of current stock price and substitutes each of these into the p/l calculator to give the rough idea of a p/l graph. 

    fig=plt.figure()
    ax=fig.add_subplot(111)

    a=float(current_stock_price)*0.6
    b=float(current_stock_price)*1.4


    #create list of the stockprices to be tested 
    data=np.arange(a, b, 0.25)

    #create empty list to populate with theh profit value at each point
    profit_points=np.zeros(len(data), dtype='f') 

    i=0

    while i <= (len(data)-1): 

        profit1=pl_calculator(entrance_price=entrance_price1, closing_price=data[i], number_shares=number_shares1,\
                commission_shares=0.1, commission_minimum=8, dividend_amount=dividend1,\
                name=name, longshort=longshort1)

        profit2=pl_calculator(entrance_price=entrance_price2, closing_price=data[i], number_shares=number_shares2,\
                commission_shares=0.1, commission_minimum=8, dividend_amount=dividend2,\
                name=name, longshort=longshort2)


        #append the profit at this particular price to a list
        profit_points[i]=profit1[0]+profit2[0]



        i+=1 

    ax.plot(data, profit_points) 
    ax.plot(current_stock_price, profit_current, 'ro', label='Current Position')                
    ax.plot(closing_price, profit_chosen, 'g^', label='Chosen Closing Position') 

    cursor = Cursor(ax, useblit=True, color='k', linewidth=1)   

    ax.grid(axis='both')


    plt.xlabel('%s($)' %name)
    plt.ylabel('P/L ($)') 
    plt.title('P/L') 
    plt.legend(loc='upper right', numpoints=1)

    plt.show() 







#run cases for current stock price and chosen stock price 
trade1_current=pl_calculator(entrance_price=entrance_price1,     closing_price=current_stock_price, number_shares=number_shares1,\
                commission_shares=0.1, commission_minimum=8,    dividend_amount=dividend1,\
                name=name, longshort=longshort1) 

trade2_current=pl_calculator(entrance_price=entrance_price2,    closing_price=current_stock_price, number_shares=number_shares2,\
                commission_shares=0.1, commission_minimum=8,   dividend_amount=dividend2,\
                name=name, longshort=longshort2)

trade1_chosen=pl_calculator(entrance_price=entrance_price1,   closing_price=closing_price, number_shares=number_shares1,\
                commission_shares=0.1, commission_minimum=8,   dividend_amount=dividend1,\
                name=name, longshort=longshort1) 

trade2_chosen=pl_calculator(entrance_price=entrance_price2,   closing_price=closing_price, number_shares=number_shares2,\
                commission_shares=0.1, commission_minimum=8,   dividend_amount=dividend2,\
                name=name, longshort=longshort2)





profit_current=trade1_current[0]+trade2_current[0]
profit_chosen=trade1_chosen[0]+trade2_chosen[0]

dividend=trade1_current[3]+trade2_current[3]

movement=closing_price/current_stock_price*100-100

print '%s: $%.2f' %(name, current_stock_price)
print '@ $%.2f (%.2f%%)' %(closing_price, movement)
print 'Dividend Payment: $%.2f' %dividend
print 'Profit: $%.2f'%(trade1_current[0]+trade2_current[0])


print_graph(current_stock_price, profit_current, profit_chosen, closing_price, name) 
bigboat
  • 249
  • 1
  • 4
  • 13

2 Answers2

0

You can subclass the matplotlib.ticker.ScalarFormatter to add the percentage number as follows:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker

class MyPercentageFormatter(matplotlib.ticker.ScalarFormatter):
    def __init__(self,origval, offset=False, mathText=True):
        self.origval = float(origval)
        matplotlib.ticker.ScalarFormatter.__init__(self,useOffset=offset,useMathText=mathText)
    def pprint_val(self, x):
        val = matplotlib.ticker.ScalarFormatter.pprint_val(self, x)
        perc = x/self.origval*100
        newval = val + "({perc:.0f}%)".format(perc=perc)
        return newval


x = np.arange(50)
y = np.sin(x/10.)

fig, ax = plt.subplots()
ax.xaxis.set_major_formatter(MyPercentageFormatter(20))
ax.plot(x,y)

plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
0

You need to use a custom Formatter class to do this. I would recommend something like FuncFormatter for your particular case since you are relying on an external "original" value. You could do something like

from matplotlib.ticker import FuncFormatter
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: '{}({:d}%)'.format(x, int(x / original * 100.0 + 0.5))))

Colors can be partially implemented using LaTeX, but only if you use a backed that supports that sort of rendering. You can also create your own labels in the axes and move them around to simulate the ticks, but I suspect that this is too much work for a limited payoff. The relevant post is here: Partial coloring of text in matplotlib.

Minor nitpick, consider using fig, ax = plt.subplots() instead of doing it on two lines.

Community
  • 1
  • 1
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264