tl;dr

I made a fare calculator that will tell you how much money you should put on your card given your current balance.


Working in the city means having to travel within the city. Because the buildings are packed densely, you can choose from a wide array of transportation methods. Depending on a combination of parameters (distance, weather, $$$) you can choose how you will get from point A to point B. I’ve walked, biked, and taken the subway.

The subway tends to be a reliable and relatively cheap option that stretches across all five boroughs of the city. It’s not a 100% perfect solution but it gets the job done. There are however a list of grievances with using the subway. Fare hikes, crazy people, rude people, dirty stations, unplanned downtime are just a few items of note but for a low flat rate it’s not that bad.

With the latest fare hike of March 2013, there are a series of changes that prevent you from achieving a $0.00 balance without effort. You used to be able to walk up to an MTA MetroCard vending machine, feed it $20 and be able to use all of it. Now when you purchase a new card, it deducts $1 from your $20, applies a 5% bonus to the remaining $19 giving you a total balance of $19.95. A single subway ride is $2.50, meaning that a balance of $19.95 yields 7 rides. When those 7 rides are used, the remaining balance is $2.45. How annoying is that! That card is useless until you add more money. So you add another $20 and now your balance is $23.45 (good for 9 rides) which leaves you with a balance of $0.95 after those 9 rides are used. When are we ever going to have a $0 balance?

Unless you enjoy donating $2.45 to the MTA, you’re going to be holding onto that card. That card will always have some strange, left-over, unusable balance that will keep haunting you every time you use the subway. If you hope to zero out your MetroCard simply by adding $20 every time you go to the vending machine, it will never happen.

The Cycle
  • Initial $20 has unusable balance of $2.45

  • Another $20 yields $23.45 with unusable balance of $0.95

  • Another $20 yields $21.95 with unusable balance of $1.95

  • Another $20 yields $22.95 with unusable balance of $0.45

  • Another $20 yields $21.45 with unusable balance of $1.45

  • Another $20 yields $22.45 with unusable balance of $2.45

Oh look at that, you’re back to a useless $2.45! The MTA is profiting from the breakage of discarded cards with remaining balances and new card fees.

This isn’t a problem without a solution. If you take a look at the fare details, you get the high level view of how an MTA MetroCard vending machine works. You can only pay in increments of $0.05, any amount paid over $5 has a 5% bonus, and you must subtract $1 from the pre-bonus amount paid if the card you are crediting is a new card.

So in regards to the initial $2.45 remaining balance you could quickly zero your card out by adding $0.05. However, you wouldn’t be "benefiting" from the 5% bonus for payments over $5.

With these simple rules, I made a fare calculator using a small bit of javascript, that will tell you how much money you should put on your card given your current balance.

Here’s the source:

fare-calc.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>MTA Fare Calculator</title>
  <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
  <div class="header">
    <h3>MTA Fare Calculator</h3>
  </div>
  <form class="form-horizontal" role="form">
    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <div class="radio">
          <label><input type="radio" name="cardType" value="new" checked> New Card ($1.00 fee)</label>
        </div>
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <div class="radio">
          <label><input type="radio" name="cardType" value="existing"> Existing Card</label>
        </div>
      </div>
    </div>

    <div class="form-group">
      <label for="existingBalance" class="col-sm-2 control-label">Existing balance</label>
      <div class="col-sm-10">
        <input id="existingBalance" name="existingBalance" class="form-control" type="number" placeholder="Existing balance" disabled value="0" min=0 max=1000 step=0.01>
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-primary" type="submit">Calculate</button>
      </div>
    </div>

  </form>

  <div class="row">
    <div class="col-sm-offset-2 col-sm-10">
      <table class="table table-condensed table-hover">
        <thead><tr><th>You should pay</th><th>With Bonus</th><th>For Balance</th><th>Number of rides</th></tr></thead>
        <tbody></tbody>
      </table>
    </div>
  </div>
</div>

<script src="https://code.jquery.com/jquery.min.js"></script>
<script>
  (function() {

    var baseFare = 2.50;
    var newCardFee = 1.00;
    var minAmountForBonus=5;
    var bonus=0.05;
    var machineIncrements = 0.05;

    var cash = function(credit, existing) {
      existing = isNaN(existing) ? 0 : parseFloat(existing);
      var amountBonus = 0;
      if (credit >= minAmountForBonus) {
        amountBonus = parseFloat((credit * bonus).toFixed(2));
      }
      var newBalance = credit + amountBonus + existing;
      return  {
        whatToPay: credit,
        bonus: amountBonus,
        balance: newBalance
      };
    };

    $('body').on('submit', 'form', function(e) {
      e.preventDefault();

      var form = $(this).serialize().split("&");

      var existingBalance = $('#existingBalance:not([disabled])').val() || 0;

      var isNewCard = $('input[name="cardType"]:checked').val() === 'new';

      var tbody = $('tbody').empty();

      var amount = machineIncrements;
      var i = 0;
      while (amount < 120) {
        var credit = parseFloat((i++ * machineIncrements).toFixed(2));
        var card = cash(credit, existingBalance);
        var amount = card.whatToPay;
        if (isNewCard) {
          amount += 1;
        }

        if (amount > 0) {
          var trips = parseFloat(card.balance.toFixed(2)) / baseFare;
          if (trips > 0 && trips % 1 === 0) {
            var contents = ['$' + amount.toFixed(2), '$' + card.bonus.toFixed(2), '$' + card.balance.toFixed(2), trips].join('</td><td>');
            tbody.append(['<tr><td>', contents, '</td></tr>'].join(''));
          }
        }
      }
    });

    $('body').on('change', 'input[name="cardType"]', function() {
      var existing = this.value ==='existing';

      if (existing && $(this).is(':checked')) {
        $('#existingBalance').removeAttr('disabled').focus();
      } else {
        $('#existingBalance').attr('disabled', true);
      }

    });

  })();
</script>
</body>
</html>

If you plan on traveling frequently within a given week or month, there are additional ways to optimize your MTA expenditure. The 7 day unlimited is $30 and the 30 day unlimited is $112. If you find yourself paying more than these amounts on your card you should consider getting an unlimited card if your card is going to be used very frequently.

Notes

As I was testing my fare calculator, I assumed that the MTA would simply truncate values after the hundredth’s place. It turns out they are rounding to the nearest hundredth place, so at least the bonus calculation is fair.