├── __init__.py ├── pickle └── .gitignore.txt ├── .gitignore ├── profitLossGraph.py ├── statement.txt ├── prices.py ├── graph.py ├── README.md ├── depositGraph.py └── mainV2.py /__init__.py: -------------------------------------------------------------------------------- 1 | from .mainV2 import Portfolio 2 | -------------------------------------------------------------------------------- /pickle/.gitignore.txt: -------------------------------------------------------------------------------- 1 | # Ignore everything in this directory 2 | * 3 | # Except this file 4 | !.gitignore -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pickle 2 | sensData.py 3 | dividendPaid.py 4 | bfg.jar 5 | secret.txt 6 | /orders.py 7 | __pycache__ 8 | .vscode 9 | /deposits.py 10 | /orders.txt 11 | statement.txt 12 | dividends.txt -------------------------------------------------------------------------------- /profitLossGraph.py: -------------------------------------------------------------------------------- 1 | def optimizeData(l): 2 | 3 | import numpy as np 4 | 5 | def antiAliasV2(l,steps): 6 | file=[np.linspace(start=l[v],stop=l[v-1],num=steps) for v in range(len(l))] 7 | return [x for lst in file for x in lst][steps:] 8 | 9 | def biggestDataDifferenceV2(l): 10 | gaps=[abs(l[v]-l[v-1]) for v in range(len(l))] 11 | return max(gaps[1:]) 12 | 13 | def dataRange(l): 14 | return max(l)-min(l) 15 | 16 | def countProfitLoss(nList): 17 | profit=np.ma.masked_where(nList<0,nList) 18 | loss=np.ma.masked_where(nList>0,nList) 19 | return profit,loss,nList 20 | 21 | #start of optimiseData function 22 | minPart=dataRange(l)/100 23 | multiplierV2=int(biggestDataDifferenceV2(l)/10) 24 | 25 | newOne=antiAliasV2(l,multiplierV2) 26 | numpyList=np.array(newOne) 27 | return countProfitLoss(numpyList) 28 | -------------------------------------------------------------------------------- /statement.txt: -------------------------------------------------------------------------------- 1 | 1 POS112727420 2019.04.29 12:36 Buy 69 VUKE 32.4349 32.17 -18.28 0 2 | 2 POS101582781 2018.10.26 10:02 Buy 1 VMID 29.435 33.305 3.87 0 3 | 3 POS104121282 2018.12.10 10:00 Buy 5 PSN 2213.6 3054 42.02 0 4 | 4 POS101582480 2018.10.26 10:00 Buy 2 HL 1796.5 1739 -1.15 0 5 | 5 POS101582499 2018.10.26 10:00 Buy 8 INVP 473.6 418.7 -4.39 0 6 | 6 POS102186690 2018.11.06 10:00 Buy 40 VOD 153.63 149.4 -1.69 0 7 | 7 POS105530053 2019.01.04 10:00 Buy 5 MKS 253.4 176.5 -3.85 0 8 | 8 POS102224924 2018.11.06 17:52 Buy 41 EVR 576.339 351 -92.39 0 9 | 9 POS101582520 2018.10.26 10:00 Buy 20 BT 241.4 160.74 -16.13 0 10 | 10 POS101582491 2018.10.26 10:00 Buy 232 LLOY 57.6857 56.78 -2.1 0 11 | 11 POS101582545 2018.10.26 10:00 Buy 26 AV 413.662 398.1 -4.05 0 12 | 12 POS104121258 2018.12.10 10:00 Buy 10 PTEC 389.6 343.9 -4.57 0 13 | 13 POS105487268 2019.01.03 18:29 Buy 198 CREI 115.5838 113.2 -4.72 0 14 | 14 POS102853078 2018.11.16 11:45 Buy 3 HMSO 418.067 233.2 -5.55 0 15 | 15 POS103378446 2018.11.27 10:12 Buy 60 CNCT 37.3667 34.7 -1.6 0 16 | -------------------------------------------------------------------------------- /prices.py: -------------------------------------------------------------------------------- 1 | import time 2 | import os 3 | import pickle 4 | import requests 5 | import sys 6 | 7 | def addPrices(self,stockName,apiKey): 8 | class Day: 9 | def __init__(self,basePrice,amount,stockPrice,etf,dividend,deposits): 10 | if etf == False: 11 | stockPrice/=100 12 | basePrice/=100 13 | self.profit=round(((stockPrice-basePrice)*amount)+dividend,3) 14 | self.amount=amount 15 | self.stockPrice=stockPrice 16 | self.basePrice=basePrice 17 | self.dividendPaid=dividend 18 | self.totalDeposits=deposits 19 | 20 | def oneTimeConnection(stockName=stockName): 21 | 22 | todayUnixTime=time.time() 23 | def downloadFreshStockData(): 24 | try: 25 | data=requests.get(f'https://api.worldtradingdata.com/api/v1/history?symbol={stockName}.L&sort=newest&api_token={apiKey}').json()['history'] 26 | return data 27 | except IndexError: 28 | print('Connection error') 29 | sys.exit() 30 | 31 | path=os.path.join(os.path.dirname(__file__),f"pickle\\{stockName}.pickle") 32 | if stockName == "BT": 33 | stockName+=".A" 34 | try: 35 | res=pickle.load(open(path,'rb')) 36 | if todayUnixTime - os.path.getmtime(path) > 86400: 37 | res=downloadFreshStockData() 38 | print(f"Old data for {stockName}, dowloaded new one") 39 | pickle.dump(res,open(path,'wb')) 40 | except (FileNotFoundError): 41 | res = downloadFreshStockData() 42 | print("Downloaded "+str(stockName)) 43 | pickle.dump(res,open(path,'wb')) 44 | return res 45 | 46 | def newBasePrice(): 47 | if day != firstDay: 48 | bfAmount=amount 49 | newAmount,newPrice=self.ordersData[stockName][stringDay] 50 | bfPrice=basePrice 51 | totalBefore=bfAmount*bfPrice 52 | totalNew=newAmount*newPrice 53 | totalAmount=bfAmount+newAmount 54 | newBasePrice=(totalBefore+totalNew)/totalAmount 55 | return round(newBasePrice,3),totalAmount 56 | return basePrice,amount 57 | 58 | totalStockDividends=0 59 | priceData=oneTimeConnection() 60 | stockPrice=0 61 | firstDay=self.db[stockName].date 62 | strFirstDay=self.strDay(firstDay) 63 | amount=float(self.ordersData[stockName][strFirstDay][0]) 64 | basePrice=float(self.ordersData[stockName][strFirstDay][1]) 65 | etf=self.db[stockName].etf 66 | for day in self.db[stockName].history.keys(): 67 | stringDay=self.strDay(day) 68 | 69 | # add dividends 70 | if stockName in self.dividendData: 71 | if stringDay in self.dividendData[stockName]: 72 | totalStockDividends+=self.dividendData[stockName][stringDay] 73 | self.db[stockName].dividendTotal+=totalStockDividends 74 | #count new base price 75 | if stringDay in self.ordersData[stockName]: 76 | basePrice,amount=newBasePrice() 77 | #update stock price if markets were opened 78 | if stringDay in priceData: 79 | stockPrice=float(priceData[stringDay]['close']) 80 | self.db[stockName].history[day]=Day(basePrice,amount,stockPrice,etf,totalStockDividends,0) -------------------------------------------------------------------------------- /graph.py: -------------------------------------------------------------------------------- 1 | def showGraphV2(self): 2 | def findMultiplier(array): 3 | result=[] 4 | for n in range(len(array))[1:]: 5 | difference = abs(array[n-1]-array[n]) 6 | result.append(difference) 7 | longestLine=max(result) 8 | return int(longestLine/15) 9 | 10 | def antialias(array,multiplier): 11 | result=[] 12 | for n in range(len(array))[1:]: 13 | start=array[n-1] 14 | stop=array[n] 15 | step=(stop-start)/(multiplier+1) 16 | result.append(start) 17 | for _ in range(multiplier): 18 | start+=step 19 | result.append(start) 20 | result.append(array[-1]) 21 | return result 22 | 23 | def showMonths(): 24 | #list with first day of month index N 25 | fDayPositions=[] 26 | pDates=list(self.dayTotals.keys()) 27 | for day in range(len(pDates)): 28 | if pDates[day][8:10]=='01': 29 | fDayPositions.append(day) 30 | fDayPositionsX=[v*multiplier for v in fDayPositions] 31 | for n in fDayPositionsX: 32 | plt.axvline(n,color='white',alpha=0.1) 33 | 34 | def showYears(): 35 | nYPositions={} 36 | pDates=list(self.dayTotals.keys()) 37 | savedYear=pDates[0][0:4] 38 | y=min(loss)-5 39 | for d in range(len(pDates)): 40 | if pDates[d][0:4]!=savedYear: 41 | savedYear=pDates[d][0:4] 42 | nYPositions[savedYear]=d 43 | for year in nYPositions.keys(): 44 | x=nYPositions[year]*multiplier 45 | plt.axvline(x,color='white',alpha=0.5) 46 | plt.annotate(year,xy=(x+200,y)) 47 | 48 | def dividendGraph(): 49 | dividendPlotData=[] 50 | for day in self.totalDividendsDict.keys(): 51 | for _ in range(int(multiplier+1)): 52 | dividendPlotData.append(self.totalDividendsDict[day]) 53 | return dividendPlotData[multiplier:] 54 | 55 | import numpy as np 56 | from matplotlib import pyplot as plt 57 | import itertools 58 | self.finaliseData() 59 | #Decorations 60 | dValues=list(self.dayTotals.values()) 61 | plt.rc('axes', facecolor='#304154', edgecolor='#304154') 62 | plt.rc('figure',facecolor='#304154',edgecolor='#304154') 63 | plt.rc('savefig',facecolor='#304154',edgecolor='#304154') 64 | plt.rc('text',color='white') 65 | plt.rc('xtick',color='#304154') 66 | plt.rc('ytick',color='white') 67 | plt.rc('patch',edgecolor='white') 68 | #Create graph values 69 | multiplier=findMultiplier(dValues) 70 | normal=np.array(antialias(dValues,multiplier)) 71 | profit=np.ma.masked_where(normal<0,normal) 72 | loss=np.ma.masked_where(normal>0,normal) 73 | showMonths() 74 | showYears() 75 | plt.plot(profit, color = '#96C099',label='Profit') 76 | plt.plot(loss, color = '#C54E59',label='Loss') 77 | 78 | #Dividends 79 | if len(self.dividendData)>1: 80 | dividends=dividendGraph() 81 | dividendsX=np.arange(0,len(dividends)) 82 | divShadow=[normal[iN]-dividends[iN] for iN in range(len(profit))] 83 | plt.plot(divShadow, color='white',alpha=0.1) 84 | plt.fill_between(dividendsX,normal,divShadow,color='white', alpha=0.05,label='Dividends') 85 | plt.legend() 86 | plt.show() 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # moneyChamber V2 5 | 6 | > Stock portfolio with clear performance graph. 7 | 8 | 9 | 10 | ## Why use moneyChamber ? 11 | 12 | Most of stock portfolios will look like example below. 13 | 14 | [![bad portfolio](https://i.ibb.co/t8bSQYY/Figure-2.png)]() 15 | 16 | 17 | 18 | Portfolio seems to be growing, but at this case, all the growth you can see are mostly deposits. 19 | 20 | That's why I have designed and coded this Python stock portfolio, that excludes deposits and profit is based purely on stock price movement and paid dividends. 21 | 22 | [![good portfolio](https://i.ibb.co/5Lgvfkb/Figure-1.png)]() 23 | 24 | With moneyChamber you will receive much clearer overview on performance of your portfolio. 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ## How to clone moneyChamber 33 | >- Clone this repository to your local machine using 34 | ```Python 35 | git clone https://github.com/hmelino/moneyChamber.git 36 | ``` 37 | 38 | 39 | ## API key 40 | 41 | >- moneyChamber require worldtradingdata api key to download and process history stock prices. 42 | > 43 | >- FREE api key can be obtained on [worldtradingdata.com](https://www.worldtradingdata.com/) 44 | 45 | 46 | ## Statement 47 | 48 | >- All stock data are being imported from file statement.txt which looks like : 49 | 50 | ```Python 51 | 52 | 1 POS123456789 2019.04.29 12:36 Buy 69 VUKE 32.4349 32.17 -18.28 0 53 | 54 | 2 POS123456788 2018.10.26 10:02 Buy 1 VMID 29.435 33.305 3.87 0 55 | 56 | 3 POS123456787 2018.12.10 10:00 Buy 5 PSN 2213.6 3054 42.02 0 57 | 58 | ``` 59 | 60 | >- This statement can be recieved as monthly Trading212 email statement, or can be manually added/adjusted. 61 | 62 | 63 | 64 | ## How to use 65 | >Import the package 66 | ```Python 67 | from moneyChamber import Porfolio 68 | ``` 69 | > Initialize new object with Portfolio() function and use path to your .txt [statement](#statement) as argument 70 | ```Python 71 | retirementPortfolio = moneyChamber.Portfolio('statement.txt') 72 | ``` 73 | >Add your World Trading Data [api key](#api-key) 74 | 75 | ```Python 76 | retirementPortfolio.apiKey='your_own_world_trading_data_api_key' 77 | ``` 78 | > **Optionally** you can load your paid [dividends](#dividends-file) file. 79 | > ![Dividends](https://i.ibb.co/WH3mYPG/ezgif-7-5d4ddc7ad5ef.gif)] 80 | ```Python 81 | retirementPortfolio.loadDividends('dividends.txt') 82 | ``` 83 | > When all files are loaded, you can plot graph using showGraph() function 84 | ```Python 85 | retirement.showGraph() 86 | ``` 87 | 88 | ## Dividends file 89 | >To import details about paid dividends into moneyChamber, please save them in JSON style as seen below. 90 | > 91 | >{"name_of_stock":{"date_when_dividend_was_recieved":total_amount_recieved} 92 | ```JSON 93 | {"VUKE": {"2019-06-29": 5.32, "2019-10-16": 9.23, "2020-01-02": 14.36}, 94 | "VMID": {"2018-12-26": 0.22, "2019-03-27": 0.15}} 95 | ``` 96 | >MoneyChamber will automatically calculate dividend yeld and payment received per individual stock. 97 | 98 | ## Contact 99 | > - My github portfolio `https://github.com/hmelino` 100 | > 101 | >- If you have got any issues or ideas for this package, or just wanna say hello :), email me at hmelino.github@gmail.com -------------------------------------------------------------------------------- /depositGraph.py: -------------------------------------------------------------------------------- 1 | def showDepositGraph(self): 2 | def findMultiplier(array): 3 | result=[] 4 | for n in range(len(array))[1:]: 5 | difference = abs(array[n-1]-array[n]) 6 | result.append(difference) 7 | longestLine=max(result) 8 | return int(longestLine/15) 9 | 10 | def antialias(array,multiplier): 11 | result=[] 12 | for n in range(len(array))[1:]: 13 | start=array[n-1] 14 | stop=array[n] 15 | step=(stop-start)/(multiplier+1) 16 | result.append(start) 17 | for _ in range(multiplier): 18 | start+=step 19 | result.append(start) 20 | result.append(array[-1]) 21 | return result 22 | 23 | def showMonths(): 24 | #list with first day of month index N 25 | fDayPositions=[] 26 | pDates=list(self.dayTotals.keys()) 27 | for day in range(len(pDates)): 28 | if pDates[day][8:10]=='01': 29 | fDayPositions.append(day) 30 | fDayPositionsX=[v*multiplier for v in fDayPositions] 31 | for n in fDayPositionsX: 32 | plt.axvline(n,color='white',alpha=0.1) 33 | 34 | def showYears(): 35 | nYPositions={} 36 | pDates=list(self.dayTotals.keys()) 37 | savedYear=pDates[0][0:4] 38 | y=min(loss)-5 39 | for d in range(len(pDates)): 40 | if pDates[d][0:4]!=savedYear: 41 | savedYear=pDates[d][0:4] 42 | nYPositions[savedYear]=d 43 | for year in nYPositions.keys(): 44 | x=nYPositions[year]*multiplier 45 | plt.axvline(x,color='white',alpha=0.5) 46 | plt.annotate(year,xy=(x+200,y)) 47 | 48 | def dividendGraph(): 49 | dividendPlotData=[] 50 | for day in self.totalDividendsDict.keys(): 51 | for _ in range(int(multiplier+1)): 52 | dividendPlotData.append(self.totalDividendsDict[day]) 53 | return dividendPlotData[multiplier:] 54 | 55 | import numpy as np 56 | from matplotlib import pyplot as plt 57 | import itertools 58 | self.finaliseData() 59 | 60 | #Decorations 61 | dValues=list(self.dayTotals.values()) 62 | plt.rc('axes', facecolor='#304154', edgecolor='#304154') 63 | plt.rc('figure',facecolor='#304154',edgecolor='#304154') 64 | plt.rc('savefig',facecolor='#304154',edgecolor='#304154') 65 | plt.rc('text',color='white') 66 | plt.rc('xtick',color='#304154') 67 | plt.rc('ytick',color='white') 68 | plt.rc('patch',edgecolor='white') 69 | #Create graph values 70 | multiplier=findMultiplier(dValues) 71 | normal=np.array(antialias(dValues,multiplier)) 72 | profit=np.ma.masked_where(normal<0,normal) 73 | loss=np.ma.masked_where(normal>0,normal) 74 | showMonths() 75 | showYears() 76 | plt.plot(profit, color = '#96C099',label='Profit') 77 | plt.plot(loss, color = '#C54E59',label='Loss') 78 | 79 | #Dividends 80 | if len(self.dividendData)>1: 81 | dividends=dividendGraph() 82 | dividendsX=np.arange(0,len(dividends)) 83 | divShadow=[normal[iN]-dividends[iN] for iN in range(len(profit))] 84 | plt.plot(divShadow, color='white',alpha=0.1) 85 | plt.fill_between(dividendsX,normal,divShadow,color='white', alpha=0.05,label='Dividends') 86 | plt.legend() 87 | plt.rc('legend',loc='upper left') 88 | plt.show() -------------------------------------------------------------------------------- /mainV2.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import pickle 3 | import requests 4 | import sys 5 | import os 6 | import time 7 | import json 8 | 9 | today=datetime.datetime.today().date() 10 | 11 | class Portfolio: 12 | import matplotlib.pyplot 13 | 14 | plt=matplotlib.pyplot 15 | dayTotals={} 16 | oldestDay=None 17 | db={} 18 | profit=0 19 | totalDividendsDict={} 20 | apiKey=None 21 | 22 | def strDay(self,day): 23 | return datetime.datetime.strftime(day,'%Y-%m-%d') 24 | 25 | def fullCWD(self): 26 | cwd=os.getcwd() 27 | if '//' in cwd: 28 | return f'{cwd}//' 29 | return f'{cwd}/' 30 | 31 | def finaliseData(self): 32 | from moneyChamber.prices import addPrices 33 | apiKey=self.apiKey 34 | #Download and process stock prices 35 | for stock in self.db: 36 | addPrices(self,stock,apiKey) 37 | #Count daily totals for graph 38 | self.updateDayTotals() 39 | 40 | def showGraph(self): 41 | from moneyChamber.graph import showGraphV2 42 | showGraphV2(self) 43 | 44 | def showDepositGraph(self): 45 | from moneyChamber.depositGraph import showDepositGraph 46 | showDepositGraph(self) 47 | 48 | def __init__(self,statementPath): 49 | self.cwd=self.fullCWD() 50 | self.depositsData=[0] 51 | self.dividendData=[0] 52 | self.loadStatement(statementPath) 53 | 54 | 55 | def countYeld(self): 56 | class MonthlyYeld: 57 | def __init__(self,divIncome,total): 58 | self.divIncome=round(divIncome,2) 59 | self.total=round(total,2) 60 | self.yeld=round((divIncome/total)*100,3) 61 | 62 | def nextMonth(date): 63 | date-=datetime.timedelta(32) 64 | try: 65 | return (datetime.datetime(date.year,date.month,today.day).date()) 66 | except ValueError: 67 | return (datetime.datetime(date.year,date.month,today.day-3).date()) 68 | def getNewestDay(): 69 | d=list(self.dayTotals.keys())[-1] 70 | return (datetime.datetime.strptime(d,'%Y-%m-%d')).date() 71 | 72 | newestDay=getNewestDay() 73 | day=newestDay 74 | 75 | while day > self.oldestDay: 76 | totalIncome=0 77 | totalWorth=0 78 | for s in self.db: 79 | path=self.db[s].history 80 | if day in path: 81 | amount=path[day].amount 82 | bPrice=path[day].basePrice 83 | total=amount*bPrice 84 | totalIncome+=(total*self.db[s].yeld) 85 | totalWorth+=total 86 | o=MonthlyYeld(totalIncome,totalWorth) 87 | print(day,o.divIncome,o.total,o.yeld) 88 | day=nextMonth(day) 89 | 90 | def countYearlyDivYelds(self): 91 | def oldestNewestDay(): 92 | newestDay=list(path.keys())[-1] 93 | yearAgo=newestDay-datetime.timedelta(365) 94 | if yearAgo not in path: 95 | yearAgo=self.db[s].date 96 | return yearAgo,newestDay 97 | 98 | for s in self.db: 99 | path=self.db[s].history 100 | yearAgo,newestDay=oldestNewestDay() 101 | processedDay=yearAgo 102 | dividend=0 103 | totalYeld=0 104 | while processedDay != newestDay: 105 | stringDay=self.strDay(processedDay) 106 | if stringDay in self.dividendData[s]: 107 | dividend=self.dividendData[s][stringDay] 108 | yeld=dividend/(path[processedDay].amount*path[processedDay].basePrice) 109 | totalYeld+=yeld 110 | processedDay+=datetime.timedelta(1) 111 | prettyYeld=round(totalYeld,3) 112 | if self.db[s].etf == False: 113 | prettyYeld/=100 114 | self.db[s].yeld=prettyYeld 115 | 116 | def loadDeposits(self,filename): 117 | path=self.cwd+filename 118 | try: 119 | with open(path,'r') as file: 120 | self.depositsData=json.load(file) 121 | except FileNotFoundError: 122 | print(f'Cannot find file {path}') 123 | self.dividendData={} 124 | 125 | def loadDividends(self,filename): 126 | path=self.cwd+filename 127 | try: 128 | with open(path,'r') as file: 129 | self.dividendData=json.load(file) 130 | except FileNotFoundError: 131 | print(f'Cannot find file {path}') 132 | self.dividendData={} 133 | 134 | def createOrders(self): 135 | """ Create orders data from statement """ 136 | d=self.db 137 | data={d[s].name:{self.strDay(d[s].date):[d[s].amount,d[s].price]} for s in d} 138 | 139 | #adjust prices for non ETF 140 | for stock in data.keys(): 141 | etfs=self.Stock.__etfs__ 142 | if stock not in etfs: 143 | for date in data[stock].keys(): 144 | secondPart=data[stock][date] 145 | secondPart[1]*=100 146 | return data 147 | 148 | def loadOrders(self,filename): 149 | path=self.cwd+filename 150 | try: 151 | with open(path,'r') as file: 152 | self.ordersData=json.load(file) 153 | except FileNotFoundError: 154 | print(f'Cannot find {filename}') 155 | print(f'Your working directory is {os.getcwd()}') 156 | sys.exit() 157 | 158 | def updateDayTotals(self): 159 | totalDeposits=0 160 | totalDividends=0 161 | for day in range((today-self.oldestDay).days): 162 | stringDay=self.strDay(self.oldestDay+datetime.timedelta(day)) 163 | processedDay=(self.oldestDay+datetime.timedelta(day)) 164 | totalForDay=0 165 | if stringDay in self.depositsData: 166 | totalDeposits+=self.depositsData[stringDay] 167 | for stockName in self.db: 168 | if processedDay in self.db[stockName].history: 169 | totalForDay+=self.db[stockName].history[processedDay].profit 170 | if stockName in self.dividendData: 171 | if stringDay in self.dividendData[stockName]: 172 | totalDividends+=self.dividendData[stockName][stringDay] 173 | self.dayTotals[stringDay]=totalForDay 174 | self.totalDividendsDict[stringDay]=totalDividends 175 | 176 | class Stock: 177 | __etfs__=['VUKE','VMID'] 178 | def __init__ (self,l): 179 | 180 | self.date=self.processDate(l) 181 | self.buySell=l[3] 182 | self.amount=float(l[4]) 183 | self.name=l[5] 184 | self.price=float(l[6]) 185 | buyRange=(today-self.date).days 186 | self.history={(self.date+datetime.timedelta(d)):0 for d in range(buyRange)} 187 | 188 | self.updateETF() 189 | self.dividendTotal=0 190 | 191 | def processDate(self,l): 192 | return datetime.datetime.strptime(l[2],'%Y.%m.%d %H:%M').date() 193 | 194 | def updateETF(self): 195 | if self.name in self.__etfs__: 196 | self.etf=True 197 | else: 198 | self.etf=False 199 | self.price/=100 200 | 201 | def loadStatement(self,filename): 202 | def loadStatementFile(filename): 203 | 204 | path=self.cwd+filename 205 | try: 206 | data=open(path,'r') 207 | return [l.split('\t') for l in data] 208 | except FileNotFoundError: 209 | print(f'Cannot find {url}') 210 | print(f'Your working directory is {os.getcwd()}') 211 | sys.exit() 212 | 213 | statementFile=loadStatementFile(filename) 214 | # process each line in statement as separate stock 215 | for d in statementFile: 216 | self.db[d[5]]=self.Stock(d) 217 | self.ordersData=self.createOrders() 218 | self.oldestDay=min([self.db[stock].date for stock in self.db]) 219 | 220 | pass 221 | --------------------------------------------------------------------------------