Skip to content

Commit

Permalink
fixed absolute returns to start always from 0
Browse files Browse the repository at this point in the history
  • Loading branch information
MauererM committed Dec 6, 2023
1 parent 726f93e commit a0eff45
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 50 deletions.
42 changes: 6 additions & 36 deletions profit_src/analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,48 +108,14 @@ def get_asset_costs_summed(assets):
return helper.sum_lists(lists)


def calc_returns_asset_daily_absolute_analysisperiod(asset, analyzer):
def calc_returns_asset_daily_absolute_analysisperiod(asset):
"""Calculates the absolute returns of a given asset, for the analysis period
This function returns the gains (or losses) of the asset _since the start of the analysis period_.
The data is intended to be provided with a granularity of days.
:param asset: Asset-object
:return: Tuple of two lists: (date, return). The returns of the periods in the datelist. They correspond to the
returned dates, whereas the last date of the analysis-interval is given. The return is in the asset's currency
"""
# The value of the asset of today must be known, otherwise, errors are thrown, as the holding period return is
# otherwise not very meaningful.
today_dt = dateoperations.get_date_today(analyzer.get_dateformat(), datetime_obj=True)

# If there is an asset-price available, get the latest possible one that is recorded:
today_price_avail = False
ret = asset.get_latest_price_date()
if ret is not None:
latest_date, _ = ret
latest_date_dt = analyzer.str2datetime(latest_date)
# The value can be determined from most recent price!
if latest_date_dt >= today_dt: # We have a price, even for today; this is good.
today_price_avail = True

if today_price_avail is False: # transactions-data needed to get price of today
datelist_check = asset.get_trans_datelist()
pricelist_check = asset.get_trans_pricelist()
latest_date_trans = analyzer.str2datetime(datelist_check[-1])
# Only allow if the transactions contain data from today:
if latest_date_trans >= today_dt and pricelist_check[-1] > 1e-9:
today_price_avail = True

if today_price_avail is False:
# Do not repeat this warning here, it's already outputted in the relative holding period calculation function.
# print("WARNING: Cannot calculate holding period return of "
# + asset.get_filename() + " due to unavailable and missing price of today. "
# "Update the assets marketdata-file with values from today or "
# "add a price-defining update-transaction of today.")
# Return a seemingly impossible (negative!) value:
# return -1e10
# raise RuntimeError("Require price of today. Abort plotting")
pass # Allow plotting anyways

# Create new copies - just to be sure (the get-functions should already return copies)
# Get the analysis period data:
datelist = asset.get_analysis_datelist()
costlist = asset.get_analysis_costlist()
Expand All @@ -162,7 +128,7 @@ def calc_returns_asset_daily_absolute_analysisperiod(asset, analyzer):
totlist = [datelist, valuelist, costlist, payoutlist, inflowlist, outflowlist]
n = len(datelist)
if all(len(x) == n for x in totlist) is False:
raise RuntimeError("The lists must all be of equal lenghts.")
raise RuntimeError("The lists must all be of equal lengths.")

cumu_cost = list(itertools.accumulate(costlist))
cumu_payout = list(itertools.accumulate(payoutlist))
Expand All @@ -179,6 +145,10 @@ def calc_returns_asset_daily_absolute_analysisperiod(asset, analyzer):
abs_gain = value_current - inflow + payout - cost + outflow
ret.append(abs_gain)

# Shift the whole data such that the first number starts at zero (the absolute return at the beginning of the
# analysis period should - by definition - be zero).
offs = ret[0]
ret = [val-offs for val in ret]
return datelist, ret


Expand Down
25 changes: 11 additions & 14 deletions profit_src/plotting/plot_asset_returns.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ def plot_asset_total_absolute_returns_accumulated(dates, returns, fname, analyze
"""Plots the accumulated absolute returns
:param dates: List of dates
:param returns: List of day-wise, summed returns of all investments
:param fname: Name of the file/plot to be saved
:param analyzer: Analyzer-instance (cached datetime conversions)
:param config: PROFIT's config-instance
"""
# Get the full path of the file:
fname = plotting.modify_plot_path(config.PLOTS_FOLDER, fname)
Expand Down Expand Up @@ -69,6 +72,8 @@ def plot_asset_returns_individual_absolute(assetlist, fname, analyzer, config):
The plots are created on a 2x3 grid
:param assetlist: List of asset-objects
:param fname: String of desired plot filename
:param analyzer: Analyzer-instance (cached datetime conversions)
:param config: PROFIT's config-instance
"""
fname = plotting.modify_plot_path(config.PLOTS_FOLDER, fname)
# Sanity Check:
Expand Down Expand Up @@ -101,7 +106,7 @@ def plot_asset_returns_individual_absolute(assetlist, fname, analyzer, config):
ylabel = "Return (Absolute; Currency)"

dates = assetlist_plot[0].get_analysis_datelist()
returns_total = [0.0 for _ in range(len(dates))]
returns_total = [0.0] * len(dates)

for sheet_num, assets in enumerate(assetlists_sheet):

Expand All @@ -113,21 +118,13 @@ def plot_asset_returns_individual_absolute(assetlist, fname, analyzer, config):
plotidx = idx + 1
ax = fig.add_subplot(2, 3, plotidx)
try:
dates, returns = analysis.calc_returns_asset_daily_absolute_analysisperiod(asset, analyzer)
dates, returns = analysis.calc_returns_asset_daily_absolute_analysisperiod(asset)
returns_total = [a + b for a, b in zip(returns, returns_total)]
if helper.list_all_zero(returns) is False:
x = [analyzer.str2datetime(i) for i in dates]
ax.plot(x, returns, alpha=1.0, zorder=3, clip_on=False, color=config.PLOTS_COLORS[0], marker='',
label="Absolute Returns")
else:
# Skip the plotting; no date of today available.
plt.text(0.05, 0.5, "Something went wrong", horizontalalignment='left',
verticalalignment='center',
transform=ax.transAxes, fontsize=7,
bbox=dict(facecolor='w', edgecolor='k', boxstyle='round'))
x = [analyzer.str2datetime(i) for i in dates]
ax.plot(x, returns, alpha=1.0, zorder=3, clip_on=False, color=config.PLOTS_COLORS[0], marker='',
label="Absolute Returns")
except:
# Skip the plotting; no date of today available.
plt.text(0.05, 0.5, "Missing price-data of today (or other error)", horizontalalignment='left',
plt.text(0.05, 0.5, "Something went wrong", horizontalalignment='left',
verticalalignment='center',
transform=ax.transAxes, fontsize=7, bbox=dict(facecolor='w', edgecolor='k', boxstyle='round'))

Expand Down

0 comments on commit a0eff45

Please sign in to comment.