Example #1
0
def main():
    parser = argparse.ArgumentParser(
        description=
        "Parses output from TabulaPDF. You must supply both a 1099b and\n"
        "corresponding statements with the same lots. This script will\n"
        "match lots so that you get the correct purchase date and basis\n"
        "for all lots on the 1099b.\n"
        "The output is a clean csv file that can be fed into the wash sale\n"
        "calculator.\n"
        "WARNING: Doesn't handle the case where you sold part of a lot.")
    parser.add_argument('--in1099b',
                        help="1099b input file as output from TabulaPDF")
    parser.add_argument('--statements',
                        help="statement input files output from TabulaPDF",
                        nargs='+')
    parser.add_argument('-o', '--out_file')
    parsed = parser.parse_args()

    lots = []
    print parsed.statements
    for csvfile in parsed.statements:
        print 'parsing statement', csvfile
        lots.extend(parse_schwab_statement(open(csvfile)))
    lot.print_lots(lots)
    lots = remove_sold_buys(lots)

    from1099 = parse_schwab_1099b(open(parsed.in1099b))
    lot.print_lots(from1099)

    from1099 = match_lots_to_1099(lots, from1099)
    print "1099b final:"
    for outlot in from1099:
        print outlot
    lot.save_lots(from1099, parsed.out_file)
def main():
  parser = argparse.ArgumentParser(
    description=
    "Parses output from TabulaPDF. You must supply both a 1099b and\n"
    "corresponding statements with the same lots. This script will\n"
    "match lots so that you get the correct purchase date and basis\n"
    "for all lots on the 1099b.\n"
    "The output is a clean csv file that can be fed into the wash sale\n"
    "calculator.\n"
    "WARNING: Doesn't handle the case where you sold part of a lot.")
  parser.add_argument('--in1099b', help="1099b input file as output from TabulaPDF")
  parser.add_argument('--statements',
                      help="statement input files output from TabulaPDF",
                      nargs='+')
  parser.add_argument('-o', '--out_file')
  parsed = parser.parse_args()

  lots = []
  print parsed.statements
  for csvfile in parsed.statements:
    print 'parsing statement', csvfile
    lots.extend(parse_schwab_statement(open(csvfile)))
  lot.print_lots(lots)
  lots = remove_sold_buys(lots)

  from1099 = parse_schwab_1099b(open(parsed.in1099b))
  lot.print_lots(from1099)

  from1099 = match_lots_to_1099(lots, from1099)
  print "1099b final:"
  for outlot in from1099:
    print outlot
  lot.save_lots(from1099, parsed.out_file)
Example #3
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-o', '--out_file')
    parser.add_argument('-w', '--do_wash', metavar='in_file')
    parser.add_argument('-q', '--quiet', action="store_true")
    parser.add_argument('-m',
                        '--merge_split_lots',
                        action="store_true",
                        help='''Any split lots are merged back together at end.
                      This makes it easier to match the output to the input
                      lots, but can cause the buy-dates to be slightly
                      incorrect since a lot can only have a single buy date.
                      In this mode, some wash sale lots may have a loss that
                      is greater than the adjustment amount, instead of being
                      identical, i.e., only part of the loss in the lot is
                      actually a wash sale. This is expected in this mode..''')
    parser.add_argument(
        '-r',
        '--adjust_for_dollar_rounding',
        action="store_true",
        help='''Some tax software packages will round the basis,
                      proceeds and adjustment to calculate the total loss (or
                      profit). This can cause problems for wash sales which
                      instead of having a loss of $0 may now have a profit of
                      $1, which results in a warning about a wash sale lot with
                      a profit. Fix this by slightly modifying the adjustment
                      amount so that the final loss will be $0 in such cases.
                      It is safe to use this option with the merge_split_lots
                      option.''')
    parsed = parser.parse_args()

    if parsed.do_wash:
        lots = lot.load_lots(open(parsed.do_wash))
        lot.print_lots(lots, False)
        if parsed.quiet:
            logger = progress_logger.NullLogger()
        else:
            logger = progress_logger.TermLogger()
        out = perform_wash(lots, logger)

        # merge split lots back together, if asked.
        if parsed.merge_split_lots:
            out = lot.merge_split_lots(out)

        # make the adjustment safe for whole-dollar rounding arithmentic
        if parsed.adjust_for_dollar_rounding:
            lot.adjust_for_dollar_rounding(out)

        # readable text output
        print 'output:'
        lot.print_lots(out,
                       merged=parsed.merge_split_lots,
                       rounded_dollars=parsed.adjust_for_dollar_rounding)

        # CSV text output
        if parsed.out_file:
            print 'Saving final lots to', parsed.out_file
            lot.save_lots(out, open(parsed.out_file, 'w'))
Example #4
0
def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('-o', '--out_file')
  parser.add_argument('-w', '--do_wash', metavar='in_file')
  parser.add_argument('-q', '--quiet', action="store_true")
  parser.add_argument('-m', '--merge_split_lots', action="store_true",
                      help='''Any split lots are merged back together at end.
                      This makes it easier to match the output to the input
                      lots, but can cause the buy-dates to be slightly
                      incorrect since a lot can only have a single buy date.
                      In this mode, some wash sale lots may have a loss that
                      is greater than the adjustment amount, instead of being
                      identical, i.e., only part of the loss in the lot is
                      actually a wash sale. This is expected in this mode..''')
  parser.add_argument('-r', '--adjust_for_dollar_rounding', action="store_true",
                      help='''Some tax software packages will round the basis,
                      proceeds and adjustment to calculate the total loss (or
                      profit). This can cause problems for wash sales which
                      instead of having a loss of $0 may now have a profit of
                      $1, which results in a warning about a wash sale lot with
                      a profit. Fix this by slightly modifying the adjustment
                      amount so that the final loss will be $0 in such cases.
                      It is safe to use this option with the merge_split_lots
                      option.''')
  parsed = parser.parse_args()

  if parsed.do_wash:
    lots = lot.load_lots(open(parsed.do_wash))
    lot.print_lots(lots, False)
    if parsed.quiet:
      logger = progress_logger.NullLogger()
    else:
      logger = progress_logger.TermLogger()
    out = perform_wash(lots, logger)

    # merge split lots back together, if asked.
    if parsed.merge_split_lots:
      out = lot.merge_split_lots(out)

    # make the adjustment safe for whole-dollar rounding arithmentic
    if parsed.adjust_for_dollar_rounding:
      lot.adjust_for_dollar_rounding(out)

    # readable text output
    print 'output:'
    lot.print_lots(out, merged=parsed.merge_split_lots,
                   rounded_dollars=parsed.adjust_for_dollar_rounding)

    # CSV text output
    if parsed.out_file:
      print 'Saving final lots to', parsed.out_file
      lot.save_lots(out, open(parsed.out_file, 'w'))
Example #5
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-o', '--out_file')
    parser.add_argument('-w', '--do_wash', metavar='in_file')
    parser.add_argument('-q', '--quiet', action="store_true")
    parsed = parser.parse_args()

    if parsed.do_wash:
        lots = lot.load_lots(parsed.do_wash)
        lot.print_lots(lots)
        if parsed.quiet:
            logger = progress_logger.NullLogger()
        else:
            logger = progress_logger.TermLogger()
        out = perform_wash(lots, logger)
        print 'output:'
        lot.print_lots(out)
        if parsed.out_file:
            print 'Saving final lots to', parsed.out_file
            lot.save_lots(out, parsed.out_file)
Example #6
0
def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('-o', '--out_file')
  parser.add_argument('-w', '--do_wash', metavar='in_file')
  parser.add_argument('-q', '--quiet', action="store_true")
  parsed = parser.parse_args()

  if parsed.do_wash:
    lots = lot.load_lots(parsed.do_wash)
    lot.print_lots(lots)
    if parsed.quiet:
      logger = progress_logger.NullLogger()
    else:
      logger = progress_logger.TermLogger()
    out = perform_wash(lots, logger)
    print 'output:'
    lot.print_lots(out)
    if parsed.out_file:
      print 'Saving final lots to', parsed.out_file
      lot.save_lots(out, parsed.out_file)
Example #7
0
def run_test(input_csv, expected_out_csv, merge_split_lots=False,
        rounded_dollars=False):
  lots = lot.load_lots(open(input_csv))
  out = wash.perform_wash(lots, progress_logger.NullLogger())
  out.sort(cmp=wash.cmp_by_buy_date)

  # merge split lots back together, if asked.
  if merge_split_lots:
    out = lot.merge_split_lots(out)

  # make the adjustment safe for whole-dollar rounding arithmentic
  if rounded_dollars:
    lot.adjust_for_dollar_rounding(out)

  # Sort both out and expected the same way, so we can compare them.
  out.sort(cmp=wash.cmp_by_buy_date)
  out_csv = StringIO.StringIO()
  lot.save_lots(out, out_csv)

  expected = lot.load_lots(open(expected_out_csv))
  expected.sort(cmp=wash.cmp_by_buy_date)
  expected_csv = StringIO.StringIO()
  lot.save_lots(expected, expected_csv)

  # Report pass/fail
  mods = "(merged split-lots) " if merge_split_lots else ""
  mods += "(safe for whole-dollar arithmetic) " if rounded_dollars else ""
  # lot.__eq__ compares all members, including original_form_position
  # and will also include any future internal data members. So, to compare
  # the test vs expected, we use the output CSV file for both, which should
  # be invariant.
  if out_csv.getvalue() != expected_csv.getvalue():
    print "****\n%sTest failed: %s" % (mods, input_csv)
    print "Got result:"
    print out_csv.getvalue()
    print "\nExpected output:", expected_out_csv
    print expected_csv.getvalue()
  else:
    print "%sTest passed: %s" % (mods, input_csv)