leftmouseclickin: Plotting Absolute Price Oscillator (APO) Line with Python

Our Own Score

If you make a search on Google about APO Line, this is what you will see: Absolute Price Oscillator (APO) moving averages of a security’s price and is expressed as an absolute value. APO crossing above zero is considered bullish while crossing below zero is bearish.

This is the line we are going to plot with the help of the alpha vantage module. Below is the edit version of the Forex and Stock application. The new plot op method will plot the APO line after we have clicked on the Plot APO Line button. Just like the BBbands indicator line we can include various parameters in the get_apo method.

 import json from tkinter import * import tkinter.ttk as tk from alpha_vantage.foreignexchange import ForeignExchange from alpha_vantage.techindicators import TechIndicators from alpha_vantage.timeseries import TimeSeries import matplotlib.pyplot as plt from alpha_vantage.sectorperformance import SectorPerformances  win = Tk() # Create tk instance win.title("Real Forex n Stock") # Add a title win.resizable(0, 0) # Disable resizing the GUI win.configure(background='white') # change window background color  selectorFrame = Frame(win, background="white") # create the top frame to hold base and quote currency combobox selectorFrame.pack(anchor = "nw", pady = 2, padx=10) currency_label = Label(selectorFrame, text = "Select base currency / quote currency :", background="white") currency_label.pack(anchor="w") # the currency pair label  selector1Frame = Frame(win, background="white") # create the middle frame to hold base and quote currency combobox selector1Frame.pack(anchor = "nw", pady = 2, padx=10) stock_label = Label(selector1Frame, text = "Select Stock / Time Interval / Series type / Moving average type / Fast Period / Slow Period :", background="white") stock_label.pack(anchor="w") # the stock label  curr1 = tuple() # the tuple which will be populated by base and quote currency currency_list = ['AUD', 'BCH', 'BNB', 'BND', 'BTC', 'CAD', 'CHF', 'CNY', 'EOS', 'EUR', 'ETH', 'GBP', 'HKD', 'JPY', 'LTC', 'NZD', 'MYR', 'TRX', 'USD', 'USDT', 'XLM', 'XRP'] # major world currency pairs  # populate the combo box for both the base and quote currency for key in currency_list:     curr1 += (key, )  # populate the stock symbol tuple f = open("stock.txt", "r") curr2 = tuple() for line in f.readlines():     curr2 += (line.replace('\n', ''),) f.close()  # Create a combo box for base currency base_currency = StringVar() # create a string variable based = tk.Combobox(selectorFrame, textvariable=base_currency) based['values'] = curr1 based.pack(side = LEFT, padx=3)  # Create a combo box for quote currency quote_currency = StringVar() # create a string variable quote = tk.Combobox(selectorFrame, textvariable=quote_currency) quote['values'] = curr1 quote.pack(side = LEFT, padx=3)  # Create a combo box for stock items stock_symbol = StringVar() # create a string variable stock = tk.Combobox(selector1Frame, textvariable=stock_symbol) stock['values'] = curr2 stock.current(0) stock.pack(side = LEFT, padx=3)  interval = tk.Combobox(selector1Frame) interval['values'] = ('1min', '5min', '15min', '30min', '60min', 'daily', 'weekly', 'monthly') interval.current(0) interval.pack(side = LEFT, padx=3)  price_type = tk.Combobox(selector1Frame) price_type['values'] = ('close', 'open', 'high', 'low') price_type.current(0) price_type.pack(side =LEFT, padx=3)  matype_type = tk.Combobox(selector1Frame, width=37) matype_type['values'] = ('Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)') matype_type.current(0) matype_type.pack(side =LEFT, padx=3) mattype_list = ['Simple Moving Average (SMA)', 'Exponential Moving Average (EMA)', 'Weighted Moving Average (WMA)', 'Double Exponential Moving Average (DEMA', 'Triple Exponential Moving Average (TEMA)', 'Triangular Moving Average (TRIMA', 'T3 Moving Average', 'Kaufman Adaptive Moving Average (KAMA)', ' MESA Adaptive Moving Average (MAMA)']  # fill up the fast period and slow period combo boxes with integer ranging from 2 to 10,000 fa = tuple() for i in range(2, 10001):     fa += (i, )  fast_pe = tk.Combobox(selector1Frame) fast_pe['values'] = fa fast_pe.current(0) fast_pe.pack(side=LEFT, padx=3)  slow_pe = tk.Combobox(selector1Frame) slow_pe['values'] = fa slow_pe.current(0) slow_pe.pack(side=LEFT, padx=3)  # create text widget area s = StringVar() # create string variable which will be used to fill up the Forex data # create currency frame and text widget to display the incoming forex data currencyFrame = Frame(win) currencyFrame.pack(side=TOP, fill=X) currency = Label(currencyFrame) currency.pack(fill=X) text_widget = Text(currency, fg='white', background='black') text_widget.pack(fill=X) s.set("Click the find button to find out the currency exchange rate") text_widget.insert(END, s.get())  buttonFrame = Frame(win) # create a bottom frame to hold the find button buttonFrame.pack(side = BOTTOM, fill=X, pady = 6, padx=10)  # first get the api key and secret from the file f = open("alpha.txt", "r") api_key = f.readline() f.close() api_key = api_key.replace('\n', '')  def get_exchange_rate(): # this method will display the incoming forex data after the api called      try:         cc = ForeignExchange(key= api_key)         from_ = based.get()         to_ = quote.get()          countVar = StringVar()  # use to hold the character count         text_widget.tag_remove("search", "1.0", "end")  # cleared the hightlighted currency pair          if(from_ != '' and to_ != '' and from_ != to_):             data, _ = cc.get_currency_exchange_rate(from_currency=from_, to_currency=to_)             exchange_rate = dict(json.loads(json.dumps(data)))             count = 1             sell_buy = str(count) + ".) Pair : " + exchange_rate['1. From_Currency Code'] + "(" + exchange_rate['2. From_Currency Name'] + ")" + " / " + exchange_rate['3. To_Currency Code']+"(" + exchange_rate['4. To_Currency Name'] + ") : "  + str(exchange_rate['5. Exchange Rate']) + '\n'             text_widget.delete('1.0', END)  # clear all those previous text first             s.set(sell_buy)             text_widget.insert(INSERT, s.get())  # display forex rate in text widget             pos = text_widget.search(from_, "1.0", stopindex="end", count=countVar)             text_widget.tag_configure("search", background="green")             end_pos = float(pos) + float(0.7)             text_widget.tag_add("search", pos, str(end_pos))  # highlight the background of the searched currency pair             pos = float(pos) + 2.0             text_widget.see(str(pos))      except:         print("An exception occurred")  def plot_stock_echange():      try:         stock_symbol_text = stock.get() # get the selected symbol         if(stock_symbol_text!= ''):             ts = TimeSeries(key=api_key, output_format='pandas')             data, meta_data = ts.get_intraday(symbol=stock_symbol_text, interval='1min', outputsize='full')             data['4. close'].plot()             stock_title = 'Intraday Times Series for the ' + stock_symbol_text + ' stock (1 min)'             plt.title(stock_title)             plt.show()     except:         print("An exception occurred")  def plot_stock_technical():      try:         stock_symbol_text = stock.get() # get the selected stock symbol         if(stock_symbol_text!= ''):              ti = TechIndicators(key=api_key, output_format='pandas')             data, meta_data = ti.get_bbands(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), time_period=int(interval.get().replace('min', '')))             data.plot()             stock_title = 'BBbands indicator for ' + stock_symbol_text + ' ' + interval.get()             plt.title(stock_title)             plt.show()     except:         print("An exception occurred")  def plot_op(): # plot the Absolute price oscillator (APO)      try:         stock_symbol_text = stock.get() # get the selected stock symbol         if(stock_symbol_text!= ''):              ti = TechIndicators(key=api_key, output_format='pandas')             data, meta_data = ti.get_apo(symbol=stock_symbol_text, interval=interval.get(), series_type=price_type.get(), matype=mattype_list.index(matype_type.get()), fastperiod = fast_pe.get(), slowperiod= slow_pe.get())             data.plot()             stock_title = 'Absolute Price Oscillator (APO) for ' + stock_symbol_text + ' ' + interval.get()             plt.title(stock_title)             plt.show()     except ValueError:         print("An exception occurred")  def plot_sector_performance():      sp = SectorPerformances(key=api_key, output_format='pandas')     data, meta_data = sp.get_sector()     data['Rank A: Real-Time Performance'].plot(kind='bar')     plt.title('Real Time Performance (%) per Sector')     plt.tight_layout()     plt.grid()     plt.show()  def plot_ad():      try:         stock_symbol_text = stock.get()  # get the selected stock symbol         if (stock_symbol_text != ''):             ti = TechIndicators(key=api_key, output_format='pandas')             data, meta_data = ti.get_ad(symbol=stock_symbol_text, interval=interval.get())             data.plot()             stock_title = 'Chaikin A/D line values for ' + stock_symbol_text + ' ' + interval.get()             plt.title(stock_title)             plt.show()     except:         print("An exception occurred")  action_vid = tk.Button(buttonFrame, text="Calculate Exchange Rate", command=get_exchange_rate) # button used to find out the exchange rate of currency pair action_vid.pack(side=LEFT, padx=2) action_stock_plot = tk.Button(buttonFrame, text="Plot Stock", command=plot_stock_echange) # button used to plot the intra-minute stock value action_stock_plot.pack(side=LEFT, padx=2) action_technical_plot = tk.Button(buttonFrame, text="Plot Technical", command=plot_stock_technical) # button used to plot the 60 minutes stock technical value action_technical_plot.pack(side=LEFT, padx=2) action_sector_plot = tk.Button(buttonFrame, text="Plot Sector Performance", command=plot_sector_performance) # button used to plot the sector performance graph action_sector_plot.pack(side=LEFT, padx=2) action_ad_plot = tk.Button(buttonFrame, text="Plot AD Line", command=plot_ad) # button used to plot the A/D line graph action_ad_plot.pack(side=LEFT, padx=2) action_ad_op = tk.Button(buttonFrame, text="Plot APO Line", command=plot_op) # button used to plot the APO line graph action_ad_op.pack(side=LEFT, padx=3)  win.iconbitmap(r'ico.ico') win.mainloop() 

If you run the above program and then click on the ‘Plot APO Line’ button you will see the below outcome.

Like, share or follow me on Twitter.


Planet Python

codingdirectional: Create a sports score application with python

Hello and welcome back. In this chapter, we will create a small sports score application with the help of the sports.py module. We will create a simple application to retrieve the score of the NBA result for any two particular teams and prints it on the tkinter’s text widget. Before we start, you will need to download the sports.py module to your own computer. Since the module is on pypi.org all you need is to open up your windows command prompt and type in below line to download that module! As I have mentioned earlier, I am now using visual studio 2019 to develop this new python project.

 pip install sports.py 

Now just start the visual studio 2019 then type the below code into the code editor.

 import sports import json from tkinter import * import tkinter.ttk as tk  win = Tk() # Create tk instance win.title("NBA") # Add a title  win.resizable(0, 0) # Disable resizing the GUI win.configure(background='white') # change window background color  selectorFrame = Frame(win, background="white") # create top frame to hold team 1 vs team 2 combobox selectorFrame.pack(anchor = "nw", pady = 2, padx=10) match_label = Label(selectorFrame, text = "Select Team 1 vs Team 2 :", background="white") match_label.pack(anchor="w") # the team label  # Create a combo box for team 1 team1 = tk.Combobox(selectorFrame) team1.pack(side = LEFT, padx=3)  # Create a combo box for team 2 team2 = tk.Combobox(selectorFrame) team2.pack(side = LEFT, padx=3)  s = StringVar() # create string variable # create match frame and text widget to display the incoming match data matchFrame = Frame(win) matchFrame.pack(side=TOP) match = Label(matchFrame) match.pack() text_widget = Text(match, fg='white', background='black') text_widget.pack() s.set("Click the find button to find out the match result") text_widget.insert(END, s.get())  buttonFrame = Frame(win) # create a bottom frame to hold the find button buttonFrame.pack(side = BOTTOM, fill=X, pady = 6)  # fill up the combo boxes with the team name data from the text file team_tuple = tuple() f = open("TextFile1.txt", "r") for line in f.readlines():     line = line.replace('\n', '')     team_tuple += (line, ) f.close()  team1["values"] = team_tuple team1.current(1) team2["values"] = team_tuple team2.current(0)  def get_match(): # return the recent match of team 1 vs team 2         try:         match = sports.get_match(sports.BASKETBALL, team1.get(), team2.get())         text_widget.delete('1.0', END) # clear all those previous text first         s.set(match)         text_widget.insert(INSERT, s.get()) # display team match data in text widget     except:         print("An exception occurred")  action_vid = tk.Button(buttonFrame, text="Find", command=get_match) # button used to find out the team match data action_vid.pack()  win.mainloop() 

Select the debug tab then start debugging the program.

In the next chapter, we will further modify this sports score application, maybe with other module and API because there are a few shortages in this current module.

Planet Python

gamingdirectional: The final adjustment of the main menu page buttons

In this chapter, we will make a final adjustment of the main menu page buttons so they will be positioned nicely on the game scene. We need to edit three files in this chapter. We will adjust the button positions on the start scene class. from BgSprite import BgSprite from GameSprite import GameSprite from pygame.locals import * from pygame import math as mt import pygame import pygame.

Source

Planet Python

Nick Coghlan: What does “x = a + b” mean?

Shorthand notations and shared context

Guido van Rossum recently put together an excellent post talking about the value of infix binary operators in making certain kinds of operations easier to reason about correctly.

The context inspiring that post is a python-ideas discussion regarding the possibility of adding a shorthand spelling (x = a + b) to Python for the operation:

 x = a.copy() x.update(b) 

The PEP for that proposal is still in development, so I’m not going to link to it directly [1], but the paragraph above gives the gist of the idea. Guido’s article came in response to the assertion that infix operators don’t improve readability, when we have plenty of empirical evidence to show that they do.

Where this article comes from is a key point that Guido’s article mentions, but doesn’t emphasise: that those readability benefits rely heavily on implicitly shared context between the author of an expression and the readers of that expression.

Without a previous agreement on the semantics, the only possible general answer to the question “What does x = a + b mean?” is “I need more information to answer that”.

The original shared context: Algebra

If the additional information supplied is “This is an algebraic expression”, then x = a + b is expressing a constraint on the permitted values of x, a, and b.

Specifying x = a - b as an additional constraint would then further allow the reader to infer that x = a and b = 0.

The corresponding Python context: Numbers

The use case for + in Python that most closely corresponds with algebra is using it with numbers – the key differences lie in the meaning of =, rather than the meaning of +.

So if the additional information supplied is “This is a Python assignment statement; a and b are both well-behaved finite numbers”, then the reader will be able to infer that x will be the sum of the two numbers.

Inferring the exact numeric type of x would require yet more information about the types of a and b, as types implementing the numeric + operator are expected to participate in a type coercion protocol that gives both operands a chance to carry out the operation, and only raises TypeError if neither type understands the other.

The original algebraic meaning then gets expressed in Python as assert x == a + b, and successful execution of the assignment statement ensures that assertion will pass.

In this context, types implementing the + operator are expected to provide all the properties that would be expected of the corresponding mathematical concepts (a + b == b + a, a + (b + c)  == (a + b) + c, etc), subject to the limitations of performing calculations on computers that actually exist.

Another mathematical context: Matrix algebra

If the given expression used uppercase letters, as in X = A + B, then the additional information supplied may instead be “This is a matrix algebra expression”. (It’s a notational convention in mathematics that matrices be assigned uppercase letters, while lowercase letters indicate scalar values)

For matrices, addition and subtraction are defined as only being valid between matrices of the same size and shape, so if X = A - B were to be supplied as an additional constraint, then the implications would be:

  • X, A and B are all the same size and shape
  • B consists entirely of zeroes
  • X = A

The corresponding Python context: NumPy Arrays

The numpy.ndarray type, and other types implementing the same API, bring the semantics of matrix algebra to Python programming, similar to the way that the builtin numeric types bring the semantics of scalar algebra.

This means that if the additional information supplied is “This is a Python assignment statement; A and B are both matrices of the same size and shape containing well-behaved finite numbers”, then the reader will be able to infer that X will be a new matrix of the same shape and size as matrices A and B, with each element in X being the sum of the corresponding elements in A and B.

As with scalar algebra, inferring the exact numeric type of the elements of X would require more information about the types of the elements in A and B, the original algebraic meaning gets expressed in Python as assert X == A + B, successful execution of the assignment statement ensures that assertion will pass, and types implementing + in this context are expected to provide the properties that would be expected of a matrix in mathematics.

Python’s string concatenation context

Mathematics doesn’t provide a convenient infix notation for concatenating two strings together (aside from writing their names directly next to each other), so programming language designers are forced to choose one.

While this does vary across languages, the most common choice is the one that Python uses: the + operator.

This is formally a distinct operation from numeric addition, with different semantic expectations, and CPython’s C API somewhat coincidentally ended up reflecting that distinction by offering two different ways of implementing + on a type: the tp_number->nb_add and tp_sequence->sq_concat slots. (This distinction is absent at the Python level: only __add__, __radd__ and __iadd__ are exposed, and they always populate the relevant tp_number slots in CPython)

The key semantic difference between algebraic addition and string concatenation is that in algebraic addition, the order of the operands doesn’t matter (a + b == b + a), while in the string concatenation case, the order of the operands determines which items appear first in the result (e.g. "Hello" + "World" == "HelloWorld" vs "World" + "Hello" == "WorldHello"). This means that a + b == b + a being true when concatenating strings indicates that either one or both strings are empty, or else the two strings are identical.

Another less obvious semantic difference is that strings don’t participate in the type coercion protocol that is defined for numbers: if the right hand operand isn’t a string (or string subclass) instance, they’ll raise TypeError immediately, rather than letting the other operand attempt the operation.

Python’s immutable sequence concatenation context

Python goes further than merely allowing + to be used for string concatenation: it allows it to be used for arbitrary sequence concatenation.

For immutable container types like tuple, this closely parallels the way that string concatenation works: a new immutable instance of the same type is created containing references to the same items referenced by the original operands:

 >>> a = 1, 2, 3 >>> b = 4, 5, 6 >>> x = a + b >>> a (1, 2, 3) >>> b (4, 5, 6) >>> x (1, 2, 3, 4, 5, 6) 

As for strings, immutable sequences will usually only interact with other instances of the same type (or subclasses), even when the x += b notation is used as an alternative to x = x + b. For example:

 >>> x = 1, 2, 3 >>> x += [4, 5, 6] Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: can only concatenate tuple (not "list") to tuple >>> x += 4, 5, 6 >>> x (1, 2, 3, 4, 5, 6) 

In addition to str, the tuple, and bytes types implement these concatenation semantics. range and memoryview, while otherwise implementing the Sequence API, don’t support concatenation operations.

Python’s mutable sequence concatenation context

Mutable sequence types add yet another variation to the possible meanings of + in Python. For the specific example of x = a + b, they’re very similar to immutable sequences, creating a fresh instance that references the same items as the original operands:

 >>> a = [1, 2, 3] >>> b = [4, 5, 6] >>> x = a + b >>> a [1, 2, 3] >>> b [4, 5, 6] >>> x [1, 2, 3, 4, 5, 6] 

Where they diverge is that the x += b operation will modify the target sequence directly, rather than creating a new container:

 >>> a = [1, 2, 3] >>> b = [4, 5, 6] >>> x = a; x = x + b >>> a [1, 2, 3] >>> x = a; x += b >>> a [1, 2, 3, 4, 5, 6] 

The other difference is that where + remains restrictive as to the container types it will work with, += is typically generalised to work with arbitrary iterables on the right hand side, just like the MutableMapping.extend() method:

 >>> x = [1, 2, 3] >>> x = x + (4, 5, 6) Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: can only concatenate list (not "tuple") to list >>> x += (4, 5, 6) >>> x [1, 2, 3, 4, 5, 6] 

Amongst the builtins, list and bytearray implement these semantics (although bytearray limits even in-place concatenation to bytes-like types that support memoryview style access). Elsewhere in the standard library, collections.deque and array.array are other mutable sequence types that behave this way.

A brief digression back to mathematics: Multisets

Multisets are a concept in mathematics that allow for values to occur in a set more than once, with the multiset then being the mapping from the values themselves to the count of how many times that value occurs in the multiset (with a count of zero or less being the same as the value being omitted from the set entirely).

While they don’t natively use the x = a + b notation the way that scalar algebra and matrix algebra do, the key point regarding multisets that’s relevant to this article is the fact that they do have a “Sum” operation defined, and the semantics of that operation are very similar to those used for matrix addition: element wise summation for each item in the multiset. If a particular value is only present in one of the multisets, that’s handled the same way as if it were present with a count of zero.

And back to Python once more: collections.Counter

Since Python 2.7 and 3.1, Python has included an implementation of the mathematical multiset concept in the form of the collections.Counter class. It uses x = a + b to denote multiset summation:

 >>> a = collections.Counter(maths=2, python=2) >>> b = collections.Counter(python=4, maths=1) >>> x = a + b >>> x Counter({'python': 6, 'maths': 3}) 

As with sequences, counter instances define their own interoperability domain, so they won’t accept arbitrary mappings for a binary + operation:

 >>> x = a + dict(python=4, maths=1) Traceback (most recent call last):   File "<stdin>", line 1, in <module> TypeError: unsupported operand type(s) for +: 'Counter' and 'dict' 

But they’re more permissive for in-place operations, accepting arbitrary mapping objects:

 >>> x += dict(python=4, maths=1) >>> x Counter({'python': 10, 'maths': 4}) 

What does all this have to do with the idea of dictionary addition?

Python’s dictionaries are quite interesting mathematically, as in mathematical terms, they’re not actually a container. Instead, they’re a function mapping between a domain defined by the set of keys, and a range defined by a multiset of values [2].

This means that the mathematical context that would most closely correspond to defining addition on dictionaries is the algebraic combination of functions. That’s defined such that (f + g)(x) is equivalent to f(x) + g(x), so the only binary in-fix operator support for dictionaries that could be grounded in an existing mathematical shared context is one where d1 + d2 was shorthand for:

 x = d1.copy() for k, rhs in d2.items():     try:         lhs = x[k]     except KeyError:         x[k] = rhs     else:         x[k] = lhs + rhs 

That has the unfortunate implication that introducing a Python-specific binary operator shorthand for dictionary copy-and-update semantics would represent a hard conceptual break with mathematics, rather than a transfer of existing mathematical concepts into the language. Contrast that with the introduction of collections.Counter (which was grounded in the semantics of mathematical multisets and borrowed its Python notation from element-wise addition on matrices), or the matrix multiplication operator (which was grounded in the semantics of matrix algebra, and only needed a text-editor-friendly symbol assigned, similar to using * instead of × for scalar multiplication and / instead of ÷ for division),

At least to me, that seems like a big leap to take for something where the in-place form already has a perfectly acceptable spelling (d1.update(d2)), and a more expression-friendly variant could be provided as a new dictionary class method:

 @classmethod def from_merge(cls, *inputs):     self = cls()     for input in inputs:         self.update(input)     return self 

With that defined, then the exact equivalent of the proposed d1 + d2 would be type(d1).from_merge(d1, d2), and in practice, you would often give the desired result type explicitly rather than inferring it from the inputs (e.g. dict.from_merge(d1, d2)).

However, the PEP is still in the very first stage of the discussion and review process, so it’s entirely possible that by the time it reaches python-dev it will be making a more modest proposal like a new dict class method, rather than the current proposal of operator syntax support.


[1] The whole point of the python-ideas phase of discussion is to get a PEP ready for a more critical review by the core development team, so it isn’t fair to the PEP author to invite wider review before they’re ready for it.
[2] The final section originally stated that arithmetic operations on mathematical functions didn’t have a defined meaning, so proposing them for Python’s dictionaries would be treading new conceptual ground. However, a reader pointed out that algebraic operations on functions are defined, and they translate to applying the functions independently to the inputs, and then performing the specified arithmetic operation on the results. The final section has been updated accordingly.

Planet Python

gamingdirectional: Put the power bar on the game scene

Finally we have came to the last chapter of this pygame project, in this chapter we will put three things on the game scene, a text which indicates what is the power level of the player, a game level indicator as well as a power bar which shows the power level of that player in the graphic form. We will need to edit three files in order to create such a mechanism. The first file we need to edit is…

Source

Planet Python