def display_summary_tax(summary_taxdata, CGTCalc, taxyear, report): """ taxdata contains a list of tuples ## Each tuplue (gbp_disposal_proceeds, gbp_allowable_costs, gbp_gains, gbp_losses, number_disposals, commissions, taxes, gbp_gross_profit, gbp_net_profit) """ ## Unpack tuple (gbp_disposal_proceeds, gbp_allowable_costs, gbp_gains, gbp_losses, number_disposals, gbp_commissions, gbp_taxes, gbp_gross_profit, abs_quantity, gbp_net_profit) = summary_taxdata report.write(star_line()) report.write("\n\n Summary for tax year ending 5th April %d \n" % taxyear) report.write("\n Figures in GBP\n\n") if CGTCalc: report.write("Disposal Proceeds = %s, Allowable Costs = %s, Disposals = %d \n Year Gains = %s Year Losses = %s PROFIT = %s\n" % \ (pretty(gbp_disposal_proceeds), pretty(gbp_allowable_costs), number_disposals, pretty(gbp_gains), pretty(gbp_losses), pretty(gbp_net_profit))) else: report.write("Gross trading profit %s, Commission paid %s, Taxes paid %s, Net profit %s\n" % \ (pretty(gbp_gross_profit), pretty(gbp_commissions), pretty(gbp_taxes), pretty(gbp_net_profit))) report.write("\nNot included: interest paid, interest received, data and other fees, internet connection,...\n hardware, software, books, subscriptions, office space, Dividend income (report seperately)\n\n") report.write("\n\n")
def display_taxes(self, taxyear, CGTCalc, reportinglevel, report=None): """ Run through each element, displaying the tax information in full Then print a summary """ assert reportinglevel in [ "VERBOSE", "CALCULATE", "NORMAL", "BRIEF", "ANNUAL" ] if report is None: report = sys.stdout ## Prints, and returns a tuple for each disposal_proceeds, allowable_costs, year_gains, year_losses, ## number_disposals, commissions, taxes, gross profit, net profit codes = self.keys() codes.sort() elements_taxdata = [ self[code].display_taxes_for_code(taxyear, CGTCalc, reportinglevel, report) for code in codes ] if len(elements_taxdata) == 0: report.write(star_line()) report.write("\n\nNo relevant trades for tax year %d\n\n" % taxyear) report.write(star_line()) return None summary_taxdata = map(sum, zip(*elements_taxdata)) assert len(summary_taxdata) == len(zero_tax_tuple) ## print the summary (always regardless of reporting level) display_summary_tax(summary_taxdata, CGTCalc, taxyear, report) report.write(star_line()) return None
def display_taxes(self, taxyear, CGTCalc, reportinglevel, report=None): """ Run through each element, displaying the tax information in full Then print a summary """ assert reportinglevel in ["VERBOSE","CALCULATE", "NORMAL", "BRIEF", "ANNUAL"] if report is None: report=sys.stdout ## Prints, and returns a tuple for each disposal_proceeds, allowable_costs, year_gains, year_losses, ## number_disposals, commissions, taxes, gross profit, net profit codes= self.keys() codes.sort() elements_taxdata=[self[code].display_taxes_for_code(taxyear, CGTCalc, reportinglevel, report) for code in codes] if len(elements_taxdata)==0: report.write(star_line()) report.write("\n\nNo relevant trades for tax year %d\n\n" % taxyear) report.write(star_line()) return None summary_taxdata=map(sum, zip(*elements_taxdata)) assert len(summary_taxdata)==len(zero_tax_tuple) ## print the summary (always regardless of reporting level) display_summary_tax(summary_taxdata, CGTCalc, taxyear, report) report.write(star_line()) return None
def _print_tax_details(self, report, reportinglevel, CGTCalc, net_profit, open_value, close_value, groupid, gbp_net_profit, open_comm, close_comm, open_tax, close_tax, allowable_costs, disposal_proceeds, commissions, taxes): code=self.closingtrade.Code currency=self.closingtrade.Currency assetclass=(getattr(self.closingtrade, "AssetClass","")) datelabel=self.closingtrade.Date.strftime('%d/%m/%Y') ## quantity will be negative for a closing sale / opening buy sign_quantity=self.closingtrade.SignQuantity abs_quantity=abs(sign_quantity) average_open_value= abs(open_value) / abs_quantity average_close_value= abs(close_value) / abs_quantity ## Labelling if sign_quantity<0: labels=("BUY", "SELL") signs=("-", "") else: labels=("OPEN SHORT", "CLOSE SHORT") signs=("+","-") if net_profit<0: pandl="LOSS" else: pandl="PROFIT" inreport=reporting_detail(reportinglevel) if inreport.extraline(): report.write(star_line()) report.write("\n") if CGTCalc: """ Example of CGT output 1. SELL: 40867 XYZ (Stock) on 17/12/2013 at EUR0.911 gives LOSS of XYZ 8,275.00 equals GBP 5,000 (or CLOSE SHORT: . Matches with OPEN SHORT: ) Matches with: BUY: SAME DAY TRADES. TRADES WITHIN 30 days SECTION 104 HOLDING. 40867 shares of XYZ bought at average price of EUR1.11333 """ if inreport.showbrieftrade(): report.write("%d: %s %d %s %s on %s at %s %s each gives %s of %s %s equals GBP %s\n" % \ (groupid, labels[1], int(abs_quantity), code, assetclass, datelabel, currency, pretty(average_close_value), pandl, currency, pretty(round(net_profit)), pretty(gbp_net_profit))) if inreport.showextra(): report.write(" Commission %s %s and taxes %s %s on %s\n"% (currency, pretty(close_comm), currency, pretty(close_tax),labels[1])) if inreport.listtrades(): report.write("Trade details:"+self.closingtrade.__repr__()+"\n") if inreport.showextra(): report.write("Total allowable cost %s %s Total disposal proceeds %s %s\n" % \ (currency, pretty(allowable_costs), currency, pretty(disposal_proceeds))) report.write("\nMatches with:\n") ## Calculation strings, build up to show how we calculated our profit or loss calc_string="%s(%d*%s) - %s - %s " % \ (signs[1], int(abs_quantity), pretty(average_close_value, commas=False), pretty(close_comm), pretty(close_tax)) if len(self.sameday)>0: sameday_quantity=int(round(abs(self.sameday.final_position()))) sameday_avg_value=self.sameday.average_value() sameday_tax=sum([trade.Tax for trade in self.sameday]) sameday_comm=sum([trade.Commission for trade in self.sameday]) sameday_calc_string="%s(%d*%s) - %s - %s " % \ (signs[0], sameday_quantity, pretty(sameday_avg_value, commas=False), pretty(sameday_comm), pretty(sameday_tax)) calc_string=calc_string+sameday_calc_string if inreport.showextra(): report.write("SAME DAY TRADE(S) Matches with %s of %d %s at average of %s %s each \n Commissions %s %s Taxes %s %s \n" % \ (labels[0], sameday_quantity, code, currency, pretty(sameday_avg_value), currency, pretty(sameday_comm), currency, pretty(sameday_tax))) if inreport.listtrades(): report.write("\nTrades:\n") self.sameday.print_trades_and_parents(report) if len(self.withinmonth)>0: withinmonth_quantity=int(abs(round((self.withinmonth.final_position())))) withinmonth_avg_value=self.withinmonth.average_value() withinmonth_tax=sum([trade.Tax for trade in self.withinmonth]) withinmonth_comm=sum([trade.Commission for trade in self.withinmonth]) tradecount=len(self.withinmonth) (startdate,enddate)=self.withinmonth.range_of_dates() withinmonth_calc_string="%s(%d*%s) - %s - %s " % \ (signs[0], withinmonth_quantity, pretty(withinmonth_avg_value, commas=False), pretty(withinmonth_comm), pretty(withinmonth_tax)) calc_string=calc_string+withinmonth_calc_string if inreport.showextra(): report.write("SUBSEQUENT %d TRADE(S) Within 30 days between %s and %s: Matches with %s of %d %s at of %s %s each \n Commissions %s %s Taxes %s %s \n" % \ (tradecount, str(startdate.date()), str(enddate.date()), labels[0], withinmonth_quantity, code, currency, pretty(withinmonth_avg_value), currency, pretty(withinmonth_comm), currency, pretty(withinmonth_tax))) if inreport.listtrades(): report.write("\nTrades:\n") self.withinmonth.print_trades_and_parents(report) if len(self.s104)>0: s104_quantity=int(round(abs(self.s104.final_position()))) s104_avg_value=self.s104.average_value() s104_tax=sum([trade.Tax for trade in self.s104]) s104_comm=sum([trade.Commission for trade in self.s104]) tradecount=len(self.s104) (startdate,enddate)=self.s104.range_of_dates() parent_quantity=self.s104.total_including_parents() s104_calc_string="%s(%d*%s) - %s - %s " % \ (signs[0], s104_quantity, pretty(s104_avg_value, commas=False), pretty(s104_comm), pretty(s104_tax)) calc_string=calc_string+s104_calc_string if inreport.showextra(): report.write("PRO-RATA SECTION 104: Quantity %f %s allocated from total holding of %s, made up of %d trades between %s and %s\n At average value of %s %s Commissions %s %s Taxes %s %s \n" % \ ( s104_quantity, code, pretty(parent_quantity), len(self.s104), str(startdate.date()), str(enddate.date()), currency, pretty(s104_avg_value), currency, pretty(s104_comm), currency, pretty(s104_tax))) if inreport.listtrades(): report.write("\nTrades:\n") self.s104.print_trades_and_parents(report) if inreport.showcalcs(): ## Show full calculations report.write("\nCALCULATION: "+calc_string+" = %s \n" % pretty(round(net_profit))) else: """ Example of non CGT output SELL 40867 RSA (Stock) on 17/12/2013 at EUR0.911 gives net LOSS of EUR 8,275 equals GBP5,000.0 AVERAGE price EUR . Total commission: EUR Total tax: EUR """ if inreport.showbrieftrade(): report.write("%d: %s of %d %s %s on %s at %s %s each Net %s of %s %s equals GBP %s\n" % \ (groupid, labels[1], int(abs_quantity), code, assetclass, datelabel, currency, pretty(average_close_value), pandl, currency, pretty(round(net_profit)), pretty(gbp_net_profit))) if inreport.listtrades(): report.write("Trade details:"+self.closingtrade.__repr__()+"\n") tradecount=len(self.s104) (startdate,enddate)=self.s104.range_of_dates() parent_quantity=self.s104.total_including_parents() ## Calculation strings, build up to show how we calculated our profit or loss calc_string="%s(%d*%s) - %s - %s " % \ (signs[1], int(abs_quantity), pretty(average_close_value, commas=False), pretty(close_comm), pretty(close_tax)) closing_calc_string="%s(%d*%s) - %s - %s " % \ (signs[0], int(abs_quantity), pretty(average_open_value, commas=False), pretty(open_comm), pretty(open_tax)) calc_string=calc_string+closing_calc_string if inreport.showextra(): report.write("\n%s at average value %s each between %s and %s. Total round-trip commission %s %s, and taxes %s %s" % \ (labels[0], pretty(average_open_value), str(startdate.date()), str(enddate.date()), currency, pretty(commissions), currency, pretty(taxes))) if inreport.listtrades(): ## Trade by trade breakdown report.write("\nTrades:\n") self.s104.print_trades_and_parents(report) if inreport.showcalcs(): ## calculations report.write("\nCALCULATION: "+calc_string+" = %s \n" % pretty(round(net_profit))) if inreport.extraline(): report.write("\n")
def calculatetax(all_trades, all_positions=None, CGTCalc=True, reportfile=None, reportinglevel="NORMAL", fxsource="DATABASE"): """ Calculate the tax all_trades is a TradeList object all_positions is an optional PositionList object which we use to check consistency with trades CGTCalc = True means we use same day and 30 day matching before S104 matching False means we use only S104; effectively calculating average cost for each trade reportinglevel - ANNUAL - summary for each year, BRIEF- plus one line per trade, NORMAL - plus matching details per trade, CALCULATE - as normal plus calculations VERBOSE - full breakdown of subtrade matching reportfile- text file we dump answers into. If omitted will print to screen. fxsource will indicate source of data used by FXData function as appropriate """ assert reportinglevel in ["VERBOSE", "CALCULATE", "NORMAL", "BRIEF", "ANNUAL"] if reportfile is None: reportfile="the screen." report=sys.stdout else: report = open(reportfile, "w") print("Report will be written to %s" % reportfile) ### Check against positions if all_positions is not None: breaklist=compare_trades_and_positions(all_trades, all_positions) if len(breaklist)>0: print("Breaks. Should be none except perhaps for FX rates.") print(breaklist) else: print("Trades and positions consistent") ### Add TradeID's all_trades.add_tradeids() ## Get FX data print("Getting fx data") all_currencies=all_trades.all_currencies() fx_dict=FXDict(all_currencies, fxsource) all_trades.add_fxdict_rates(fx_dict) ## Do various preprocessing measures trade_dict_bycode=all_trades.separatecode() trade_dict_bycode.add_cumulative_data() trade_dict_bycode.generate_pseduo_trades() ## Create a tax dictionary containing the trade data taxcalc_dict=TaxCalcDict(trade_dict_bycode) ## Do the trade matching print("Matching trades") taxcalc_dict.allocate_dict_trades(CGTCalc) ## Consistency check - this should never fail breaklist=compare_trades_and_positions(all_trades, taxcalc_dict.umatched_as_positions()) if len(breaklist)>0: print("BREAKS between final positions and those implied by trades. Something gone horribly wrong!") print(breaklist) raise Exception("Breaks occured!") else: print("Passed consistency check") ## What tax years are our trades for taxyears=taxcalc_dict.tax_year_span() for taxyear in taxyears: report.write(star_line()) report.write("\n TAX YEAR: %d \n\n" % taxyear) ## Display taxes taxcalc_dict.display_taxes(taxyear, CGTCalc, reportinglevel, report) if reportfile is not "the screen": report.close() print("Report finished") return taxcalc_dict
def calculatetax(all_trades, all_positions=None, CGTCalc=True, reportfile=None, reportinglevel="NORMAL", fxsource="DATABASE"): """ Calculate the tax all_trades is a TradeList object all_positions is an optional PositionList object which we use to check consistency with trades CGTCalc = True means we use same day and 30 day matching before S104 matching False means we use only S104; effectively calculating average cost for each trade reportinglevel - ANNUAL - summary for each year, BRIEF- plus one line per trade, NORMAL - plus matching details per trade, CALCULATE - as normal plus calculations VERBOSE - full breakdown of subtrade matching reportfile- text file we dump answers into. If omitted will print to screen. fxsource will indicate source of data used by FXData function as appropriate """ assert reportinglevel in ["VERBOSE", "CALCULATE", "NORMAL", "BRIEF", "ANNUAL"] if reportfile is None: reportfile="the screen." report=sys.stdout else: report = open(reportfile, "w") print "Report will be written to %s" % reportfile ### Check against positions if all_positions is not None: breaklist=compare_trades_and_positions(all_trades, all_positions) if len(breaklist)>0: print "Breaks. Should be none except perhaps for FX rates." print breaklist else: print "Trades and positions consistent" ### Add TradeID's all_trades.add_tradeids() ## Get FX data print "Getting fx data" all_currencies=all_trades.all_currencies() fx_dict=FXDict(all_currencies, fxsource) all_trades.add_fxdict_rates(fx_dict) ## Do various preprocessing measures trade_dict_bycode=all_trades.separatecode() trade_dict_bycode.add_cumulative_data() trade_dict_bycode.generate_pseduo_trades() ## Create a tax dictionary containing the trade data taxcalc_dict=TaxCalcDict(trade_dict_bycode) ## Do the trade matching print "Matching trades" taxcalc_dict.allocate_dict_trades(CGTCalc) ## Consistency check - this should never fail breaklist=compare_trades_and_positions(all_trades, taxcalc_dict.umatched_as_positions()) if len(breaklist)>0: print "BREAKS between final positions and those implied by trades. Something gone horribly wrong!" print breaklist raise Exception("Breaks occured!") else: print "Passed consistency check" ## What tax years are our trades for taxyears=taxcalc_dict.tax_year_span() for taxyear in taxyears: report.write(star_line()) report.write("\n TAX YEAR: %d \n\n" % taxyear) ## Display taxes taxcalc_dict.display_taxes(taxyear, CGTCalc, reportinglevel, report) if reportfile is not "the screen": report.close() print "Report finished" return taxcalc_dict