Skip to content

Instantly share code, notes, and snippets.

@pathikrit
Last active February 18, 2025 18:48
Show Gist options
  • Select an option

  • Save pathikrit/35030c3253e4a1a5b7f163ed7f668242 to your computer and use it in GitHub Desktop.

Select an option

Save pathikrit/35030c3253e4a1a5b7f163ed7f668242 to your computer and use it in GitHub Desktop.

Revisions

  1. pathikrit revised this gist Feb 18, 2025. 3 changed files with 92 additions and 121 deletions.
    58 changes: 58 additions & 0 deletions extend_history.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,58 @@
    pv_export_long_history = '~/Downloads/pv_export_long_history.csv'
    overrides = {
    'RSBY': 'LCSIX',
    'LCDS': 'DFSVX',
    'MCDS': 'VOE',
    'SCDS': 'SPYV',
    'NIXT': 'SPY',
    'EZBC': cash,
    'SPYU': 'UPRO',
    'MFUT': 'ASFYX',
    'AHLT': 'ASFYX',
    'TFPN': 'ASFYX',
    'QIS': 'LCSIX',
    'VFLO': 'LEXCX',
    'ASMF': 'ASFYX',
    'CAOS': cash,
    'RSBT': 'ASFYX',
    'HYGI': 'HYG',
    'CTA': 'LCSIX',
    'CRIT': 'XME',
    'DISV': 'DISVX',
    'HGER': 'LCSIX',
    'UPAR': 'DBC',
    'FLSP': 'QSPIX',
    'PFIX': 'TIPZ',
    'KMLM': 'ASFYX',
    'GOVZ': 'ZROZ',
    'CCRV': 'LCSIX',
    'KRBN': cash,
    'FCPI': 'BTAL',
    'AVUV': 'DFSVX',
    'DBMF': 'ASFYX',
    'IVOL': 'TIPZ',
    'DYNF': 'USMV',
    'IETC': 'PPA',
    'DFEN': 'PPA',
    'COWZ': 'LEXCX',
    'NANR': 'IEO',
    'CIBR': cash,
    'AIRR': 'PKB',
    'FMF': 'ASFYX',
    'WTMF': 'ASFYX',
    'USDU': 'UUP',
    'RSBA': 'MNA',
    'AVES': 'DFEVX',
    'GOLY': 'IAU',
    }
    overrides_df = pl.DataFrame({'Symbol': list(overrides.keys()), 'Symbol Override': list(overrides.values())})
    portfolio = (portfolio
    .join(overrides_df, on='Symbol', how='left')
    .group_by(pl.coalesce(pl.col('Symbol Override'), pl.col('Symbol')).alias('Symbol'))
    .agg(pl.sum('Weight'))
    .sort(pl.col('Weight'), descending=True)
    )

    portfolio.write_csv(pv_export_long_history)
    print(f'Wrote {len(portfolio)} securities to {pv_export_long_history}')
    portfolio
    121 changes: 0 additions & 121 deletions fidelity_to_portfolio_vizualizer.ipynb
    Original file line number Diff line number Diff line change
    @@ -1,121 +0,0 @@
    {
    "cells": [
    {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
    "import polars as pl\n",
    "\n",
    "fidelity_export = '~/Downloads/Portfolio_Positions_Sep-29-2024.csv'\n",
    "pv_export = '~/Downloads/pv_export.csv'\n",
    "account_name = 'Personal'\n",
    "cash = '^CASHUS'\n",
    "\n",
    "def money_col(name): return pl.col(name).str.replace_all(r'[\\$,]', '').cast(pl.Float32)\n",
    "\n",
    "portfolio = (pl\n",
    " .read_csv(fidelity_export)\n",
    " .filter(pl.col('Account Name') == account_name)\n",
    " .filter(~pl.col('Symbol').str.starts_with(' -')) # remove options\n",
    " .with_columns([\n",
    " pl.col('Symbol').str.replace_all(r'^(SPAXX|Pending).*', cash), # Cash positions\n",
    " money_col('Last Price').alias('Price'),\n",
    " pl.col('Quantity'),\n",
    " money_col('Current Value'),\n",
    " ])\n",
    " # Sometimes current value is empty (e.g when security is in margin)\n",
    " .with_columns(pl.coalesce(pl.col('Current Value'), pl.col('Quantity') * pl.col('Price')).alias('Value'))\n",
    ")\n",
    "\n",
    "total = portfolio['Value'].sum()\n",
    "portfolio = (portfolio\n",
    " .with_columns((100 * pl.col('Value')/total).alias('Weight'))\n",
    " # sometimes the same security is listed multiple times e.g. when it is loaned out\n",
    " .group_by(pl.col('Symbol'))\n",
    " .agg(pl.sum('Weight'))\n",
    " .sort(pl.col('Weight'), descending=True)\n",
    ")\n",
    "portfolio.write_csv(pv_export)\n",
    "print(f'Wrote {len(portfolio)} securities to {pv_export}')\n",
    "total, portfolio"
    ]
    },
    {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
    "# Sometimes a security is too new to be properly backtested;\n",
    "# we override with a similar ticker that has a longer history\n",
    "\n",
    "pv_export_long_history = '~/Downloads/pv_export_long_history.csv'\n",
    "overrides = {\n",
    " 'RSBY': 'LCSIX',\n",
    " 'LCDS': 'DFSVX',\n",
    " 'MCDS': 'VOE',\n",
    " 'SCDS': 'SPYV',\n",
    " 'NIXT': 'SPY',\n",
    " 'EZBC': cash,\n",
    " 'SPYU': 'UPRO',\n",
    " 'MFUT': 'ASFYX',\n",
    " 'AHLT': 'ASFYX',\n",
    " 'TFPN': 'ASFYX',\n",
    " 'QIS': 'LCSIX',\n",
    " 'VFLO': 'LEXCX',\n",
    " 'ASMF': 'ASFYX',\n",
    " 'CAOS': cash,\n",
    " 'RSBT': 'ASFYX',\n",
    " 'HYGI': 'HYG',\n",
    " 'CTA': 'LCSIX',\n",
    " 'CRIT': 'XME',\n",
    " 'DISV': 'DISVX',\n",
    " 'HGER': 'LCSIX',\n",
    " 'UPAR': 'DBC',\n",
    " 'FLSP': 'QSPIX',\n",
    " 'PFIX': 'TIPZ',\n",
    " 'KMLM': 'ASFYX',\n",
    " 'GOVZ': 'ZROZ',\n",
    " 'CCRV': 'LCSIX',\n",
    " 'KRBN': cash,\n",
    " 'FCPI': 'BTAL',\n",
    " 'AVUV': 'DFSVX',\n",
    " 'DBMF': 'ASFYX',\n",
    " 'IVOL': 'TIPZ',\n",
    " 'DYNF': 'USMV',\n",
    " 'IETC': 'PPA',\n",
    " 'DFEN': 'PPA',\n",
    " 'COWZ': 'LEXCX',\n",
    " 'NANR': 'IEO',\n",
    " 'CIBR': cash,\n",
    " 'AIRR': 'PKB',\n",
    " 'FMF': 'ASFYX',\n",
    " 'WTMF': 'ASFYX',\n",
    " 'USDU': 'UUP',\n",
    "}\n",
    "overrides_df = pl.DataFrame({'Symbol': list(overrides.keys()), 'Symbol Override': list(overrides.values())})\n",
    "portfolio = (portfolio\n",
    " .join(overrides_df, on='Symbol', how='left')\n",
    " .group_by(pl.coalesce(pl.col('Symbol Override'), pl.col('Symbol')).alias('Symbol'))\n",
    " .agg(pl.sum('Weight'))\n",
    " .sort(pl.col('Weight'), descending=True)\n",
    ")\n",
    "\n",
    "portfolio.write_csv(pv_export_long_history)\n",
    "print(f'Wrote {len(portfolio)} securities to {pv_export_long_history}')\n",
    "portfolio"
    ]
    }
    ],
    "metadata": {
    "kernelspec": {
    "display_name": "Python 3 (ipykernel)",
    "language": "python",
    "name": "python3"
    }
    },
    "nbformat": 4,
    "nbformat_minor": 2
    }
    34 changes: 34 additions & 0 deletions fidelity_to_pv.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    import polars as pl

    fidelity_export = '~/Downloads/Portfolio_Positions_Feb-18-2025.csv'
    pv_export = '~/Downloads/pv_export.csv'
    account_name = 'Personal'
    cash = '^CASHUS'

    def money_col(name): return pl.col(name).str.replace_all(r'[$,]', '').cast(pl.Float32)

    portfolio = (pl
    .read_csv(fidelity_export)
    .filter(pl.col('Account Name') == account_name)
    .filter(~pl.col('Symbol').str.starts_with(' -')) # remove options
    .with_columns([
    pl.col('Symbol').str.replace_all(r'^(SPAXX|Pending).*', cash), # Cash positions
    money_col('Last Price').alias('Price'),
    pl.col('Quantity'),
    money_col('Current Value'),
    ])
    # Sometimes current value is empty (e.g when security is in margin)
    .with_columns(pl.coalesce(pl.col('Current Value'), pl.col('Quantity') * pl.col('Price')).alias('Value'))
    )

    total = portfolio['Value'].sum()
    portfolio = (portfolio
    .with_columns((100 * pl.col('Value')/total).alias('Weight'))
    # sometimes the same security is listed multiple times e.g. when it is loaned out
    .group_by(pl.col('Symbol'))
    .agg(pl.sum('Weight'))
    .sort(pl.col('Weight'), descending=True)
    )
    portfolio.write_csv(pv_export)
    print(f'Wrote {len(portfolio)} securities to {pv_export}')
    total, portfolio
  2. pathikrit created this gist Oct 4, 2024.
    121 changes: 121 additions & 0 deletions fidelity_to_portfolio_vizualizer.ipynb
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,121 @@
    {
    "cells": [
    {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
    "import polars as pl\n",
    "\n",
    "fidelity_export = '~/Downloads/Portfolio_Positions_Sep-29-2024.csv'\n",
    "pv_export = '~/Downloads/pv_export.csv'\n",
    "account_name = 'Personal'\n",
    "cash = '^CASHUS'\n",
    "\n",
    "def money_col(name): return pl.col(name).str.replace_all(r'[\\$,]', '').cast(pl.Float32)\n",
    "\n",
    "portfolio = (pl\n",
    " .read_csv(fidelity_export)\n",
    " .filter(pl.col('Account Name') == account_name)\n",
    " .filter(~pl.col('Symbol').str.starts_with(' -')) # remove options\n",
    " .with_columns([\n",
    " pl.col('Symbol').str.replace_all(r'^(SPAXX|Pending).*', cash), # Cash positions\n",
    " money_col('Last Price').alias('Price'),\n",
    " pl.col('Quantity'),\n",
    " money_col('Current Value'),\n",
    " ])\n",
    " # Sometimes current value is empty (e.g when security is in margin)\n",
    " .with_columns(pl.coalesce(pl.col('Current Value'), pl.col('Quantity') * pl.col('Price')).alias('Value'))\n",
    ")\n",
    "\n",
    "total = portfolio['Value'].sum()\n",
    "portfolio = (portfolio\n",
    " .with_columns((100 * pl.col('Value')/total).alias('Weight'))\n",
    " # sometimes the same security is listed multiple times e.g. when it is loaned out\n",
    " .group_by(pl.col('Symbol'))\n",
    " .agg(pl.sum('Weight'))\n",
    " .sort(pl.col('Weight'), descending=True)\n",
    ")\n",
    "portfolio.write_csv(pv_export)\n",
    "print(f'Wrote {len(portfolio)} securities to {pv_export}')\n",
    "total, portfolio"
    ]
    },
    {
    "cell_type": "code",
    "execution_count": null,
    "metadata": {},
    "outputs": [],
    "source": [
    "# Sometimes a security is too new to be properly backtested;\n",
    "# we override with a similar ticker that has a longer history\n",
    "\n",
    "pv_export_long_history = '~/Downloads/pv_export_long_history.csv'\n",
    "overrides = {\n",
    " 'RSBY': 'LCSIX',\n",
    " 'LCDS': 'DFSVX',\n",
    " 'MCDS': 'VOE',\n",
    " 'SCDS': 'SPYV',\n",
    " 'NIXT': 'SPY',\n",
    " 'EZBC': cash,\n",
    " 'SPYU': 'UPRO',\n",
    " 'MFUT': 'ASFYX',\n",
    " 'AHLT': 'ASFYX',\n",
    " 'TFPN': 'ASFYX',\n",
    " 'QIS': 'LCSIX',\n",
    " 'VFLO': 'LEXCX',\n",
    " 'ASMF': 'ASFYX',\n",
    " 'CAOS': cash,\n",
    " 'RSBT': 'ASFYX',\n",
    " 'HYGI': 'HYG',\n",
    " 'CTA': 'LCSIX',\n",
    " 'CRIT': 'XME',\n",
    " 'DISV': 'DISVX',\n",
    " 'HGER': 'LCSIX',\n",
    " 'UPAR': 'DBC',\n",
    " 'FLSP': 'QSPIX',\n",
    " 'PFIX': 'TIPZ',\n",
    " 'KMLM': 'ASFYX',\n",
    " 'GOVZ': 'ZROZ',\n",
    " 'CCRV': 'LCSIX',\n",
    " 'KRBN': cash,\n",
    " 'FCPI': 'BTAL',\n",
    " 'AVUV': 'DFSVX',\n",
    " 'DBMF': 'ASFYX',\n",
    " 'IVOL': 'TIPZ',\n",
    " 'DYNF': 'USMV',\n",
    " 'IETC': 'PPA',\n",
    " 'DFEN': 'PPA',\n",
    " 'COWZ': 'LEXCX',\n",
    " 'NANR': 'IEO',\n",
    " 'CIBR': cash,\n",
    " 'AIRR': 'PKB',\n",
    " 'FMF': 'ASFYX',\n",
    " 'WTMF': 'ASFYX',\n",
    " 'USDU': 'UUP',\n",
    "}\n",
    "overrides_df = pl.DataFrame({'Symbol': list(overrides.keys()), 'Symbol Override': list(overrides.values())})\n",
    "portfolio = (portfolio\n",
    " .join(overrides_df, on='Symbol', how='left')\n",
    " .group_by(pl.coalesce(pl.col('Symbol Override'), pl.col('Symbol')).alias('Symbol'))\n",
    " .agg(pl.sum('Weight'))\n",
    " .sort(pl.col('Weight'), descending=True)\n",
    ")\n",
    "\n",
    "portfolio.write_csv(pv_export_long_history)\n",
    "print(f'Wrote {len(portfolio)} securities to {pv_export_long_history}')\n",
    "portfolio"
    ]
    }
    ],
    "metadata": {
    "kernelspec": {
    "display_name": "Python 3 (ipykernel)",
    "language": "python",
    "name": "python3"
    }
    },
    "nbformat": 4,
    "nbformat_minor": 2
    }