<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Huzaifa Zahoor</title>
    <description>The latest articles on DEV Community by Huzaifa Zahoor (@nutshellcrypto).</description>
    <link>https://dev.to/nutshellcrypto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4163162%2F09d88fb0-c7d9-452c-b03b-b70d66cbc907.png</url>
      <title>DEV Community: Huzaifa Zahoor</title>
      <link>https://dev.to/nutshellcrypto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nutshellcrypto"/>
    <language>en</language>
    <item>
      <title>Multisig Wallets for Developers: Thinking in m-of-n Before You Trust One Key</title>
      <dc:creator>Huzaifa Zahoor</dc:creator>
      <pubDate>Tue, 06 Oct 2026 08:44:05 +0000</pubDate>
      <link>https://dev.to/nutshellcrypto/multisig-wallets-for-developers-thinking-in-m-of-n-before-you-trust-one-key-4e2g</link>
      <guid>https://dev.to/nutshellcrypto/multisig-wallets-for-developers-thinking-in-m-of-n-before-you-trust-one-key-4e2g</guid>
      <description>&lt;p&gt;A single private key is a single point of failure. If you've ever run a system with one database and no replica, you already know the feeling. Multisig wallets apply a familiar fix: spread control across several independent keys and require a quorum before anything happens.&lt;/p&gt;

&lt;p&gt;This post looks at multisig the way you'd look at any distributed system: thresholds, failure modes, and the state you must not lose. For the full beginner walkthrough, including use cases and an MPC comparison, see this &lt;a href="https://nutshellcrypto.com/multisig-wallet" rel="noopener noreferrer"&gt;plain-English guide to multisig wallets&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  m-of-n is a threshold policy
&lt;/h2&gt;

&lt;p&gt;A multisig wallet is described as m-of-n: n keys exist, and any m of them must sign before funds move. A 2-of-3 wallet has three keys and needs two signatures.&lt;/p&gt;

&lt;p&gt;That gives you two tolerances to reason about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Theft tolerance:&lt;/strong&gt; an attacker needs m keys, so up to m - 1 stolen keys can't move funds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loss tolerance:&lt;/strong&gt; you only need m keys to spend, so you can lose up to n - m keys and still recover.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a tiny script that prints both for common setups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tolerances&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;need 1 &amp;lt;= m &amp;lt;= n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;setup&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-of-&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stolen_keys_survivable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lost_keys_survivable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;tolerances&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output tells the story quickly. 1-of-2 survives a lost key but not a stolen one. 2-of-2 is the reverse: one stolen key is harmless, but one lost key locks the funds. 2-of-3 survives either one lost key or one stolen key, which is why it's the usual starting point for personal cold storage. 3-of-5 survives two of either, at the cost of managing five devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  How signing actually flows
&lt;/h2&gt;

&lt;p&gt;On Bitcoin, multisig is built into the script system. BIP 11 and BIP 16 standardized it years ago, and Taproot added the &lt;code&gt;OP_CHECKSIGADD&lt;/code&gt; opcode for multisig policies (BIP 342). The day-to-day workflow uses PSBTs, Partially Signed Bitcoin Transactions (BIP 174). One device builds the transaction, it gets passed around (often as a file or QR code to an offline signer), each signer adds a signature, and once m signatures are attached it can be broadcast.&lt;/p&gt;

&lt;p&gt;On Ethereum, an ordinary account is controlled by one key, so multisig lives in a smart contract instead. Safe is the best-known example: the contract stores a list of owners and a confirmation threshold, and only executes a transaction once enough owners approve. That makes things like rotating owners possible, but it also means the contract code is part of what you trust, and deploying it costs gas.&lt;/p&gt;

&lt;h2&gt;
  
  
  The state you must back up
&lt;/h2&gt;

&lt;p&gt;This is the part people miss. On Bitcoin, seed phrases alone may not be enough to rebuild a multisig wallet. You also need the wallet configuration, usually called the output descriptor, which records which public keys are involved and what the threshold is. Lose it and recovery gets much harder, even if you still hold enough seeds.&lt;/p&gt;

&lt;p&gt;A sensible backup checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each seed phrase stored separately, ideally on hardware wallets from different vendors.&lt;/li&gt;
&lt;li&gt;The wallet descriptor or configuration file, copied to several places.&lt;/li&gt;
&lt;li&gt;Plain-language instructions for whoever might need to recover the funds later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Trade-offs worth naming
&lt;/h2&gt;

&lt;p&gt;Multisig removes the single key as a failure point, but it adds others:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity.&lt;/strong&gt; More devices, more backups, more locations. Complexity is where humans make mistakes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coordinator software.&lt;/strong&gt; The app that builds addresses and collects signatures matters. Prefer well-known, open-source tools that let you export your setup and move elsewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fees.&lt;/strong&gt; Spending from a Bitcoin multisig usually costs more than single-sig, and bigger quorums cost more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Overkill for small balances.&lt;/strong&gt; For everyday amounts, a single-sig hardware wallet is usually the simpler choice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MPC wallets are a related option. They split one key into shares and produce a single signature off-chain, while multisig uses independent keys whose approvals are checked on-chain. Different trust model, similar goal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test before you trust it
&lt;/h2&gt;

&lt;p&gt;Treat a new multisig like a staging deploy. Receive a small amount, then spend it by signing with two different keys. Only move anything that matters once that round trip works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;m-of-n means you survive up to m - 1 stolen keys and up to n - m lost keys.&lt;/li&gt;
&lt;li&gt;2-of-3 is the common default because it tolerates one lost or one stolen key.&lt;/li&gt;
&lt;li&gt;On Bitcoin, back up the descriptor, not just the seeds.&lt;/li&gt;
&lt;li&gt;On Ethereum, multisig is a smart contract, so its code joins your trust base.&lt;/li&gt;
&lt;li&gt;Always do a small test spend before trusting a setup with real funds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://nutshellcrypto.com/multisig-wallet" rel="noopener noreferrer"&gt;Read the full guide on NutshellCrypto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is educational content only, not financial or investment advice. Crypto is volatile and you can lose money.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was written with AI assistance.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>security</category>
      <category>beginners</category>
      <category>crypto</category>
    </item>
    <item>
      <title>Crypto Tax Loss Harvesting for Developers: Find Your Losing Lots with a Few Lines of Python</title>
      <dc:creator>Huzaifa Zahoor</dc:creator>
      <pubDate>Mon, 05 Oct 2026 08:44:06 +0000</pubDate>
      <link>https://dev.to/nutshellcrypto/crypto-tax-loss-harvesting-for-developers-find-your-losing-lots-with-a-few-lines-of-python-89p</link>
      <guid>https://dev.to/nutshellcrypto/crypto-tax-loss-harvesting-for-developers-find-your-losing-lots-with-a-few-lines-of-python-89p</guid>
      <description>&lt;p&gt;If you hold crypto and you write code, tax season is mostly a data problem. Which coins did you buy, when, at what price, and which of those lots are worth less today? Answer that cleanly and one of the more useful year-end moves, tax loss harvesting, gets a lot less scary.&lt;/p&gt;

&lt;p&gt;This post walks through the idea in plain terms and then shows a tiny script for spotting harvestable losses in your own records. For the full rules, limits, and a worked example, see this &lt;a href="https://nutshellcrypto.com/crypto-tax-loss-harvesting" rel="noopener noreferrer"&gt;guide to crypto tax loss harvesting in the US&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea in one paragraph
&lt;/h2&gt;

&lt;p&gt;In the US, the IRS treats crypto as property. When you sell, swap, or spend it, you realize a gain or loss: what you got minus your cost basis. A coin that is down on paper gives you nothing to deduct. Harvesting means deliberately realizing that loss, usually by selling, so it offsets gains elsewhere. Losses beyond your gains can reduce up to $3,000 of ordinary income a year ($1,500 if married filing separately), and the rest carries forward to later years.&lt;/p&gt;

&lt;p&gt;Two details trip people up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Crypto-to-crypto swaps count as disposals.&lt;/strong&gt; Swapping one token for another can realize a loss (or a gain) just like selling for dollars.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It mostly defers tax.&lt;/strong&gt; If you buy back in, your new basis is lower, so a later sale may show a bigger gain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why this is really a data problem
&lt;/h2&gt;

&lt;p&gt;Which units you sell decides how big your loss is. IRS FAQs allow specific identification of units at the time of sale, or a standing order with your broker; otherwise a wallet-by-wallet first-in, first-out default applies. So if you bought the same coin at three different prices, selling the most expensive lot first gives the biggest harvestable loss.&lt;/p&gt;

&lt;p&gt;That only works if your lot data is trustworthy. The classic failure point is wallet-to-wallet transfers, where cost basis quietly goes missing. Brokers now report on Form 1099-DA, but for 2026 and later basis is generally reported only for coins bought after 2025 and kept with that same broker. Coins moved in from elsewhere can show up with no basis at all, and self-custody or DeFi activity still has to be reported by you.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal lot scanner
&lt;/h2&gt;

&lt;p&gt;Here's a small sketch. Export your buys to a CSV with &lt;code&gt;asset,date,qty,cost_usd&lt;/code&gt; columns, plug in current prices, and it lists every lot that is under water, sorted by the size of the loss, with a short-term or long-term flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;

&lt;span class="n"&gt;prices&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ETH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2400.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SOL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;120.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# fill in current prices yourself
&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lots.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cost_usd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;bought&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;prices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
        &lt;span class="n"&gt;pnl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;cost&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;term&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;long&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="nf"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;bought&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;365&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;short&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;asset&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bought&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;term&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; bought &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bought&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;term&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;-term  unrealized &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pnl&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; USD&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prices above are placeholders, not real quotes. The holding-period flag matters because short-term losses (held a year or less) offset short-term gains first, and long-term losses offset long-term gains first, before crossing over. The day count is a rough cut, so check edge cases against your own records.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wash-sale question, carefully
&lt;/h2&gt;

&lt;p&gt;For stocks, the wash-sale rule blocks a loss if you buy back substantially identical securities within 30 days. As of October 5, 2026, that rule covers stock and securities, and ordinary crypto held directly like bitcoin or ether generally isn't caught by it. Spot crypto ETF shares are different: treat them as covered.&lt;/p&gt;

&lt;p&gt;There's a catch worth knowing. A bill introduced in September 2026, H.R. 10357, would extend the rule to traded digital assets for sales after September 14, 2026, if it is enacted as written. It has cleared a House committee but isn't law. So "sell and immediately rebuy" now carries real uncertainty. The full guide covers where that bill stands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Losses only count once realized, and the sale has to happen in the tax year you want the loss in, which for most people means by December 31.&lt;/li&gt;
&lt;li&gt;Your edge is clean data: dated lots, amounts, and dollar values, especially across wallet transfers.&lt;/li&gt;
&lt;li&gt;Check your exchange's cost-basis or lot-selection settings before you sell.&lt;/li&gt;
&lt;li&gt;Don't sell just for the tax break; fees, spreads, and a bad investment call can outweigh the saving.&lt;/li&gt;
&lt;li&gt;Canada works differently, with a superficial loss rule and no $3,000-style income deduction.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://nutshellcrypto.com/crypto-tax-loss-harvesting" rel="noopener noreferrer"&gt;Read the full guide on NutshellCrypto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is educational content, not tax or financial advice. Tax rules and pending legislation change, so check current IRS guidance or a tax professional before acting.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was written with AI assistance.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>crypto</category>
      <category>python</category>
      <category>fintech</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
