|
| 1 | +""" |
| 2 | +This file performs portfolio rebalancing, presenting the results |
| 3 | +confluent with Vanguard Switch procedures. For example, if you hold |
| 4 | +assets "A", "B", and "C" on Vanguard, each with total values in your |
| 5 | +portfolio of 2000, 3000, and 4000, respectively. By running: |
| 6 | +`rebalance A 2000 B 3000 C 4000` |
| 7 | +You will be presented with: |
| 8 | +`{'A': 1.0, 'B': 0.0, 'C': -0.25}`, |
| 9 | +indicating that you should sell 25% of "C", placing 100% of the sale |
| 10 | +into "A" and 0% into "B". |
| 11 | +""" |
| 12 | + |
| 13 | +import sys |
| 14 | + |
| 15 | +from portfolio_rebalance import __version__ |
| 16 | + |
| 17 | +__author__ = "David Simmons" |
| 18 | +__copyright__ = "David Simmons" |
| 19 | +__license__ = "MIT" |
| 20 | + |
| 21 | + |
| 22 | +def rebalance(dict): |
| 23 | + """Portfolio rebalancer |
| 24 | +
|
| 25 | + Args: |
| 26 | + kwargs (Dict): Dictionary of assets and total portfolio value |
| 27 | +
|
| 28 | + Returns: |
| 29 | + Dict: Dictionary of assets and percentage to be sold/bought |
| 30 | + """ |
| 31 | + total = 0.0 |
| 32 | + for key, value in dict.items(): |
| 33 | + total += value |
| 34 | + |
| 35 | + rebalanced_asset_value = total / len(dict) |
| 36 | + rebalanced_assets = {} |
| 37 | + |
| 38 | + for key, value in dict.items(): |
| 39 | + rebalanced_assets[key] = rebalanced_asset_value / dict[key] - 1 |
| 40 | + |
| 41 | + value_of_buys = 0 |
| 42 | + for key, value in rebalanced_assets.items(): |
| 43 | + if value > 0: |
| 44 | + value_of_buys += value |
| 45 | + else: |
| 46 | + pass |
| 47 | + |
| 48 | + for key, value in rebalanced_assets.items(): |
| 49 | + if value > 0: |
| 50 | + print(value) |
| 51 | + rebalanced_assets[key] /= value_of_buys |
| 52 | + else: |
| 53 | + pass |
| 54 | + |
| 55 | + return rebalanced_assets |
| 56 | + |
| 57 | +def parse_args(args): |
| 58 | + """Parse command line parameters |
| 59 | +
|
| 60 | + Args: |
| 61 | + args (List[str]): command line parameters as list of strings |
| 62 | + (for example ``["--help"]``). |
| 63 | +
|
| 64 | + Returns: |
| 65 | + :obj:`argparse.Namespace`: command line parameters namespace |
| 66 | + """ |
| 67 | + keys = [] |
| 68 | + values = [] |
| 69 | + for asset in args: |
| 70 | + try: |
| 71 | + is_float = float(asset) |
| 72 | + except ValueError: |
| 73 | + is_float = False |
| 74 | + if isinstance(asset, str) and not is_float: |
| 75 | + keys.append(asset) |
| 76 | + elif is_float: |
| 77 | + values.append(float(asset)) |
| 78 | + else: |
| 79 | + raise Exception() |
| 80 | + if len(keys) != len(values): |
| 81 | + raise Exception() |
| 82 | + |
| 83 | + assets = {} |
| 84 | + for idx, el in enumerate(keys): |
| 85 | + assets[el] = values[idx] |
| 86 | + |
| 87 | + return assets |
| 88 | + |
| 89 | + |
| 90 | +def main(args): |
| 91 | + kwargs = parse_args(args) |
| 92 | + print(rebalance(kwargs)) |
| 93 | + |
| 94 | + |
| 95 | +def run(): |
| 96 | + main(sys.argv[1:]) |
| 97 | + |
| 98 | + |
| 99 | +if __name__ == "__main__": |
| 100 | + run() |
0 commit comments