Example #1
0
def test_records(account_checking, asset_krw):
    with Transaction.create() as t:
        record = Record.create(
            created_at=parse_date('2016-03-14'), transaction=t,
            account=account_checking, asset=asset_krw,
            quantity=1000)

        # Make sure the record type has been set implictly
        assert RecordType.deposit == record.type

    with Transaction.create() as t:
        record = Record.create(
            created_at=parse_date('2016-03-14'), transaction=t,
            account=account_checking, asset=asset_krw,
            quantity=-2000)

        # Make sure the record type has been set implictly
        assert RecordType.withdraw == record.type

    with Transaction.create() as t:
        record = Record.create(
            created_at=parse_date('2016-03-14'), transaction=t,
            account=account_checking, asset=asset_krw,
            quantity=3000, type=RecordType.balance_adjustment)

        # Make sure the record type has been set explicitly
        assert RecordType.balance_adjustment == record.type
Example #2
0
def test_portfolio_balance(account_checking, account_savings, account_sp500,
                           asset_krw, asset_sp500):
    """Ensures a portfolio, which is essentially a collection of accounts,
    calculates its balance correctly.
    """
    portfolio = Portfolio()
    portfolio.base_asset = asset_krw
    portfolio.add_accounts(account_checking, account_savings, account_sp500)

    assert portfolio.balance(parse_date('2016-05-20')) == {}

    deposit(account_checking, asset_krw, 1500, parse_date('2016-05-01'))
    deposit(account_savings, asset_krw, 3000, parse_date('2016-05-01'))
    deposit(account_sp500, asset_sp500, 120, parse_date('2016-05-01'))

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 4500, asset_sp500: 120}

    deposit(account_savings, asset_krw, 4000, parse_date('2016-05-02'))
    deposit(account_savings, asset_krw, 5000, parse_date('2016-05-03'))

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 13500, asset_sp500: 120}

    balance_adjustment(account_savings, asset_krw, 10000,
                       parse_date('2016-05-04'))

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 11500, asset_sp500: 120}

    db.session.delete(portfolio)
    db.session.commit()
Example #3
0
def import_fund(code, from_date, to_date):
    """Imports fund data from KOFIA.

    :param code: e.g., KR5223941018
    :param from_date: e.g., 2016-01-01
    :param to_date: e.g., 2016-02-28
    """
    provider = Kofia()

    app = create_app(__name__)
    with app.app_context():
        asset = get_asset_by_fund_code(code)

        # FIXME: Target asset should also be determined by asset.data.code
        base_asset = Asset.query.filter_by(name='KRW').first()

        data = provider.fetch_data(
            code, parse_date(from_date), parse_date(to_date))
        for date, unit_price, quantity in data:
            log.info('Import data on {}', date)
            unit_price /= 1000.0
            try:
                AssetValue.create(
                    asset=asset, base_asset=base_asset,
                    evaluated_at=date, close=unit_price,
                    granularity=Granularity.day,
                    source='kofia')
            except IntegrityError:
                log.warn('Identical record has been found for {}. Skipping.',
                         date)
                db.session.rollback()
Example #4
0
def test_records(account_checking, asset_krw):
    with Transaction.create() as t:
        record = Record.create(created_at=parse_date('2016-03-14'),
                               transaction=t,
                               account=account_checking,
                               asset=asset_krw,
                               quantity=1000)

        # Make sure the record type has been set implictly
        assert RecordType.deposit == record.type

    with Transaction.create() as t:
        record = Record.create(created_at=parse_date('2016-03-14'),
                               transaction=t,
                               account=account_checking,
                               asset=asset_krw,
                               quantity=-2000)

        # Make sure the record type has been set implictly
        assert RecordType.withdraw == record.type

    with Transaction.create() as t:
        record = Record.create(created_at=parse_date('2016-03-14'),
                               transaction=t,
                               account=account_checking,
                               asset=asset_krw,
                               quantity=3000,
                               type=RecordType.balance_adjustment)

        # Make sure the record type has been set explicitly
        assert RecordType.balance_adjustment == record.type
Example #5
0
def fetch_stock_values(stock_code, start_date, end_date):
    """Fetches daily stock values from Yahoo Finance."""

    start_date = date_to_datetime(
        parse_date(start_date if start_date is not None else -30 * 3600 * 24))
    end_date = date_to_datetime(
        parse_date(end_date if end_date is not None else 0))

    if start_date > end_date:
        raise ValueError('start_date must be equal to or less than end_date')

    provider = Yahoo()
    rows = provider.asset_values(
        stock_code, start_date, end_date, Granularity.day)

    for row in rows:
        # TODO: Write a function to handle this for generic cases
        # TODO: Convert the timestamp to an ISO format
        # NOTE: The last column is data source. Not sure if this is an elegant
        # way to handle this.

        # FIXME: Think of a better way to handle this
        dt = row[0].isoformat()

        print(', '.join([dt] + [str(c) for c in row[1:]] + ['yahoo']))
Example #6
0
def fetch_stock_values(stock_code, start_date, end_date):
    """Fetches daily stock values from Yahoo Finance."""

    start_date = date_to_datetime(
        parse_date(start_date if start_date is not None else -30 * 3600 * 24))
    end_date = date_to_datetime(
        parse_date(end_date if end_date is not None else 0))

    if start_date > end_date:
        raise ValueError("start_date must be equal to or less than end_date")

    provider = Yahoo()
    rows = provider.asset_values(stock_code, start_date, end_date,
                                 Granularity.day)

    for row in rows:
        # TODO: Write a function to handle this for generic cases
        # TODO: Convert the timestamp to an ISO format
        # NOTE: The last column is data source. Not sure if this is an elegant
        # way to handle this.

        # FIXME: Think of a better way to handle this
        dt = row[0].isoformat()

        print(", ".join([dt] + [str(c) for c in row[1:]] + ["yahoo"]))
Example #7
0
def import_fund(code, from_date, to_date):
    """Imports fund data from KOFIA.

    :param code: e.g., KR5223941018
    :param from_date: e.g., 2016-01-01
    :param to_date: e.g., 2016-02-28
    """
    provider = Kofia()

    app = create_app(__name__)
    with app.app_context():
        asset = get_asset_by_fund_code(code)

        # FIXME: Target asset should also be determined by asset.data.code
        base_asset = Asset.query.filter_by(name="KRW").first()

        data = provider.fetch_data(code, parse_date(from_date),
                                   parse_date(to_date))
        for date, unit_price, quantity in data:
            log.info("Import data on {}", date)
            unit_price /= 1000.0
            try:
                AssetValue.create(
                    asset=asset,
                    base_asset=base_asset,
                    evaluated_at=date,
                    close=unit_price,
                    granularity=Granularity.day,
                    source="kofia",
                )
            except IntegrityError:
                log.warn("Identical record has been found for {}. Skipping.",
                         date)
                db.session.rollback()
Example #8
0
def import_stock_values(code, from_date, to_date):
    """Import stock price information."""
    app = create_app(__name__)
    with app.app_context():
        # NOTE: We assume all Asset records are already in the database, but
        # this is a temporary workaround. We should implement some mechanism to
        # automatically insert an Asset record when it is not found.
        import_stock_values_(code, parse_date(from_date), parse_date(to_date))
Example #9
0
def test_kofia_get_request_body():
    provider = Kofia()
    body = provider.get_request_body(
        'KR5223941018', parse_date('2016-06-02'), parse_date('2016-06-03'))

    # TODO: Parse XML for assertion
    assert '20160602' in body
    assert '20160603' in body
Example #10
0
def test_kofia_get_request_body():
    provider = Kofia()
    body = provider.get_request_body(
        'KR5223941018', parse_date('2016-06-02'), parse_date('2016-06-03'))

    # TODO: Parse XML for assertion
    assert '20160602' in body
    assert '20160603' in body
Example #11
0
def request_import_stock_values_handler(event, context):
    codes = ["AMD", "AMZN", "BRK-A", "BRK-B", "ESRT", "NVDA", "SBUX", "SPY"]
    start_time = date_to_datetime(parse_date(-3))
    end_time = date_to_datetime(parse_date(0))

    for code in codes:
        request_import_stock_values(code, start_time, end_time)

    log.info("Requested to import stock values: {0}", ", ".join(codes))
Example #12
0
def test_date_range():
    start, end = parse_date("2016-01-01"), parse_date("2016-01-15")
    r = date_range(start, end)
    assert isinstance(r, types.GeneratorType)

    r = list(r)
    assert 14 == len(r)
    assert r[0] == parse_date("2016-01-01")
    assert r[13] == parse_date("2016-01-14")
Example #13
0
def request_import_stock_values_handler(event, context):
    codes = ['AMD', 'AMZN', 'BRK-A', 'BRK-B', 'ESRT', 'NVDA', 'SBUX', 'SPY']
    start_time = date_to_datetime(parse_date(-3))
    end_time = date_to_datetime(parse_date(0))

    for code in codes:
        request_import_stock_values(code, start_time, end_time)

    log.info('Requested to import stock values: {0}', ', '.join(codes))
Example #14
0
def test_kofia_get_request_body():
    provider = Kofia()
    body = provider.get_request_body(
        "KR5223941018", parse_date("2016-06-02"), parse_date("2016-06-03")
    )

    # TODO: Parse XML for assertion
    assert "20160602" in body
    assert "20160603" in body
Example #15
0
def test_kofia_fetch_data():
    provider = Kofia()
    from_date, to_date = parse_date("2016-05-01"), parse_date("2016-05-30")
    data = provider.fetch_data("KR5223941018", from_date, to_date)

    for date, unit_price, quantity in data:
        assert isinstance(date, datetime)
        assert from_date <= date <= to_date
        assert isinstance(unit_price, float)
        assert isinstance(quantity, float)
Example #16
0
def test_kofia_fetch_data():
    provider = Kofia()
    from_date, to_date = parse_date('2016-05-01'), parse_date('2016-05-30')
    data = provider.fetch_data('KR5223941018', from_date, to_date)

    for date, unit_price, quantity in data:
        assert isinstance(date, datetime)
        assert from_date <= date <= to_date
        assert isinstance(unit_price, float)
        assert isinstance(quantity, float)
Example #17
0
def test_account_net_worth_2(account_checking, account_sp500, asset_krw, asset_sp500):
    AssetValue.create(
        evaluated_at=parse_date('2016-02-25'), asset=asset_sp500,
        base_asset=asset_krw, granularity=Granularity.day, close=921.77)
    AssetValue.create(
        evaluated_at=parse_date('2016-02-24'), asset=asset_sp500,
        base_asset=asset_krw, granularity=Granularity.day, close=932.00)
    AssetValue.create(
        evaluated_at=parse_date('2016-02-23'), asset=asset_sp500,
        base_asset=asset_krw, granularity=Granularity.day, close=921.06)
    AssetValue.create(
        evaluated_at=parse_date('2016-02-22'), asset=asset_sp500,
        base_asset=asset_krw, granularity=Granularity.day, close=921.76)

    with Transaction.create() as t:
        Record.create(
            created_at=parse_date('2016-02-25'), transaction=t,
            account=account_sp500, asset=asset_sp500,
            quantity=1000)
        Record.create(
            created_at=parse_date('2016-02-25'), transaction=t,
            account=account_checking, asset=asset_krw,
            quantity=-1000 * 921.77)

    assert 921770 == account_sp500.net_worth(
        evaluated_at=parse_date('2016-02-25'), base_asset=asset_krw)

    assert 921770 == account_sp500.net_worth(
        evaluated_at=parse_date('2016-03-01'), approximation=True,
        base_asset=asset_krw)
Example #18
0
def test_balance(account_checking, asset_krw, asset_usd):
    assert account_checking.balance() == {}

    Record.create(
        created_at=parse_date('2016-05-01'), account=account_checking,
        asset=asset_krw, quantity=1000)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 1000}

    Record.create(
        created_at=parse_date('2016-05-02'), account=account_checking,
        asset=asset_krw, quantity=-500)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500}

    Record.create(
        created_at=parse_date('2016-05-03'), account=account_checking,
        asset=asset_usd, quantity=25)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500, asset_usd: 25}

    Record.create(
        created_at=parse_date('2016-05-04'), account=account_checking,
        asset=asset_usd, quantity=40, type=RecordType.balance_adjustment)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500, asset_usd: 40}
Example #19
0
def test_balance(account_checking, asset_krw, asset_usd):
    assert account_checking.balance() == {}

    Record.create(created_at=parse_date('2016-05-01'),
                  account=account_checking,
                  asset=asset_krw,
                  quantity=1000)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 1000}

    Record.create(created_at=parse_date('2016-05-02'),
                  account=account_checking,
                  asset=asset_krw,
                  quantity=-500)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500}

    Record.create(created_at=parse_date('2016-05-03'),
                  account=account_checking,
                  asset=asset_usd,
                  quantity=25)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500, asset_usd: 25}

    Record.create(created_at=parse_date('2016-05-04'),
                  account=account_checking,
                  asset=asset_usd,
                  quantity=40,
                  type=RecordType.balance_adjustment)
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500, asset_usd: 40}
Example #20
0
def test_account_net_worth_2(account_checking, account_sp500, asset_krw,
                             asset_sp500):
    AssetValue.create(evaluated_at=parse_date('2016-02-25'),
                      asset=asset_sp500,
                      base_asset=asset_krw,
                      granularity=Granularity.day,
                      close=921.77)
    AssetValue.create(evaluated_at=parse_date('2016-02-24'),
                      asset=asset_sp500,
                      base_asset=asset_krw,
                      granularity=Granularity.day,
                      close=932.00)
    AssetValue.create(evaluated_at=parse_date('2016-02-23'),
                      asset=asset_sp500,
                      base_asset=asset_krw,
                      granularity=Granularity.day,
                      close=921.06)
    AssetValue.create(evaluated_at=parse_date('2016-02-22'),
                      asset=asset_sp500,
                      base_asset=asset_krw,
                      granularity=Granularity.day,
                      close=921.76)

    with Transaction.create() as t:
        deposit(account_sp500, asset_sp500, 1000, parse_date('2016-02-25'), t)
        deposit(account_checking, asset_krw, -1000 * 921.77,
                parse_date('2016-02-25'), t)

    assert 921770 == account_sp500.net_worth(
        evaluated_at=parse_date('2016-02-25'), base_asset=asset_krw)

    assert 921770 == account_sp500.net_worth(
        evaluated_at=parse_date('2016-03-01'),
        approximation=True,
        base_asset=asset_krw)
Example #21
0
def test_balance(account_checking, asset_krw, asset_usd):
    assert account_checking.balance() == {}

    deposit(account_checking, asset_krw, 1000, parse_date("2016-05-01"))
    assert account_checking.balance(parse_date("2016-05-19")) == {
        asset_krw: 1000
    }

    deposit(account_checking, asset_krw, -500, parse_date("2016-05-02"))
    assert account_checking.balance(parse_date("2016-05-19")) == {
        asset_krw: 500
    }

    deposit(account_checking, asset_usd, 25, parse_date("2016-05-03"))
    assert account_checking.balance(parse_date("2016-05-19")) == {
        asset_krw: 500,
        asset_usd: 25,
    }

    balance_adjustment(account_checking, asset_usd, 40,
                       parse_date("2016-05-04"))
    assert account_checking.balance(parse_date("2016-05-19")) == {
        asset_krw: 500,
        asset_usd: 40,
    }
Example #22
0
def test_yahoo_fetch_data():
    provider = Yahoo()
    from_date, to_date = parse_date('2014-01-01'), parse_date('2015-12-31')
    data = provider.fetch_data('005380.KS', from_date, to_date)

    for date, open_, high, low, close_, volume, adj_close in data:
        assert isinstance(date, datetime)
        # assert from_date <= date <= to_date
        assert isinstance(open_, float)
        assert isinstance(high, float)
        assert isinstance(low, float)
        assert isinstance(close_, float)
        assert isinstance(volume, int)
        assert isinstance(adj_close, float)
Example #23
0
def import_sp500():
    app = create_app(__name__)
    with app.app_context():
        account_checking = Account.get(id=1001)
        account_sp500 = Account.get(id=7001)
        asset_krw = Asset.query.filter_by(name='KRW').first()
        asset_sp500 = Asset.query.filter_by(name='KB S&P500').first()

        with open('sample-data/sp500.csv') as fin:
            for line in fin:
                cols = line.split()
                if len(cols) != 5:
                    continue
                date = parse_date(cols[0], '%Y.%m.%d')
                _type = cols[1]
                quantity_krw, quantity_sp500 = \
                    [int(extract_numbers(v)) for v in cols[2:4]]

                print(cols)

                withdraw = _type == '일반입금'

                with Transaction.create() as t:
                    if withdraw:
                        Record.create(
                            created_at=date, account=account_checking,
                            asset=asset_krw, quantity=-quantity_krw,
                            transaction=t)
                    Record.create(
                        created_at=date, account=account_sp500,
                        asset=asset_sp500, quantity=quantity_sp500,
                        transaction=t)

        print(account_sp500.net_worth(make_date('2016-02-25'), target_asset=asset_krw))
Example #24
0
        def gen_records(rows):
            for row in rows:
                date = parse_date(extract_div_text(row, class_='Cell_445'),
                                  DATE_FORMAT)
                principle = etnc(row, 'Cell_451', int)
                interest = etnc(row, 'Cell_448', int)
                tax = etnc(row, 'Cell_449', int)
                fees = etnc(row, 'Cell_452', int)

                # NOTE: Early payments may cause some portion of the fees
                # to be refunded
                refunded_fees = etnc(row, 'Cell_759', int)

                returned = etnc(row, 'Cell_453', int)

                # Make sure the parsed data is correct
                try:
                    assert returned \
                        == principle + interest - (tax + fees - refunded_fees)
                except AssertionError:
                    import pdb
                    pdb.set_trace()
                    pass

                yield date, principle, interest, tax, fees - refunded_fees
Example #25
0
def test_date_to_datetime():
    date = parse_date("2018-01-13")
    dt_beginning = parse_datetime("2018-01-13 00:00:00")
    dt_end = parse_datetime("2018-01-13 23:59:59")

    assert date_to_datetime(date) == dt_beginning
    assert date_to_datetime(date, True) == dt_end
Example #26
0
def import_sp500_records():
    """Import S&P500 fund sample data. Expects a tab seprated value document.
    """
    app = create_app(__name__)
    app.app_context().push()

    account_checking = Account.get(id=1001)
    account_sp500 = Account.get(id=7001)
    asset_krw = Asset.query.filter_by(name='KRW').first()
    asset_sp500 = Asset.query.filter_by(name='KB S&P500').first()

    # Expected number of columns
    expected_col_count = 6

    with open('sample-data/sp500.csv') as fin:
        # Skip the first row (headers)
        headers = next(fin)
        col_count = len(headers.split())
        if col_count != expected_col_count:
            raise Exception(
                'Expected number of columns = {}, '
                'actual number of columns = {}'.format(
                    expected_col_count, col_count))

        for line in fin:
            cols = line.split('\t')
            if len(cols) != expected_col_count:
                continue
            date = parse_date(cols[0], '%Y.%m.%d')
            _type = cols[1]
            quantity_krw, quantity_sp500 = \
                [int(extract_numbers(v)) for v in cols[3:5]]

            log.info(', '.join([c.strip() for c in cols]))

            if not (_type == '일반입금' or _type == '일반신규'):
                log.info('Record type \'{}\' will be ignored', _type)
                continue

            with Transaction.create() as t:
                # NOTE: The actual deposit date and the buying date generally
                # differ by a few days. Need to figure out how to parse this
                # properly from the raw data.
                try:
                    Record.create(
                        created_at=date, account=account_checking,
                        asset=asset_krw, quantity=-quantity_krw,
                        transaction=t)
                except IntegrityError:
                    log.warn('Identical record exists')
                    db.session.rollback()

                try:
                    Record.create(
                        created_at=date, account=account_sp500,
                        asset=asset_sp500, quantity=quantity_sp500,
                        transaction=t)
                except IntegrityError:
                    log.warn('Identical record exists')
                    db.session.rollback()
Example #27
0
def test_portfolio_balance(account_checking, account_savings, account_sp500,
                           asset_krw, asset_sp500):
    portfolio = Portfolio()
    portfolio.base_asset = asset_krw
    portfolio.add_accounts(account_checking, account_savings, account_sp500)

    assert portfolio.balance(parse_date('2016-05-20')) == {}

    Record.create(created_at=parse_date('2016-05-01'),
                  account=account_checking,
                  asset=asset_krw,
                  quantity=1500)
    Record.create(created_at=parse_date('2016-05-01'),
                  account=account_savings,
                  asset=asset_krw,
                  quantity=3000)
    Record.create(created_at=parse_date('2016-05-01'),
                  account=account_sp500,
                  asset=asset_sp500,
                  quantity=120)

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 4500, asset_sp500: 120}

    Record.create(created_at=parse_date('2016-05-02'),
                  account=account_savings,
                  asset=asset_krw,
                  quantity=4000)
    Record.create(created_at=parse_date('2016-05-03'),
                  account=account_savings,
                  asset=asset_krw,
                  quantity=5000)

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 13500, asset_sp500: 120}

    Record.create(created_at=parse_date('2016-05-04'),
                  account=account_savings,
                  asset=asset_krw,
                  quantity=10000,
                  type=RecordType.balance_adjustment)

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 11500, asset_sp500: 120}

    db.session.delete(portfolio)
    db.session.commit()
Example #28
0
def test_account_net_worth_4(account_checking, asset_usd):
    """Ensures Account.net_worth() works with explicit `created_at`."""
    deposit(account_checking, asset_usd, 1000,
            parse_datetime('2018-08-30 23:00:00'))

    net_worth = account_checking.net_worth(
        base_asset=asset_usd, evaluated_at=parse_date('2018-08-30'))
    assert net_worth == 1000
Example #29
0
def test_net_worth_without_asset_value(request, account_sp500, asset_krw,
                                       asset_sp500):
    asset_values = AssetValue.query.filter_by(asset=asset_sp500)
    for asset_value in asset_values:
        db.session.delete(asset_value)
    db.session.commit()

    record = Record.create(
        created_at=parse_date('2016-05-27'), account=account_sp500,
        asset=asset_sp500, quantity=1000)

    with pytest.raises(AssetValueUnavailableException):
        account_sp500.net_worth(parse_date('2016-05-28'), base_asset=asset_krw)

    def teardown():
        db.session.delete(record)
        db.session.commit()
    request.addfinalizer(teardown)
Example #30
0
def test_net_worth_without_asset_value(request, account_sp500, asset_krw,
                                       asset_sp500):
    asset_values = AssetValue.query.filter_by(asset=asset_sp500)
    for asset_value in asset_values:
        db.session.delete(asset_value)
    db.session.commit()

    record = deposit(account_sp500, asset_sp500, 1000,
                     parse_date('2016-05-27'))

    with pytest.raises(AssetValueUnavailableException):
        account_sp500.net_worth(parse_date('2016-05-28'), base_asset=asset_krw)

    def teardown():
        db.session.delete(record)
        db.session.commit()

    request.addfinalizer(teardown)
Example #31
0
def import_sp500_records():
    """Import S&P500 fund sample data. Expects a tab seprated value document.
    """
    app = create_app(__name__)
    app.app_context().push()

    account_checking = Account.get(id=1001)
    account_sp500 = Account.get(id=7001)
    asset_krw = Asset.query.filter_by(name="KRW").first()
    asset_sp500 = Asset.query.filter_by(name="KB S&P500").first()

    # Expected number of columns
    expected_col_count = 6

    with open("sample-data/sp500.csv") as fin:
        # Skip the first row (headers)
        headers = next(fin)
        col_count = len(headers.split())
        if col_count != expected_col_count:
            raise Exception("Expected number of columns = {}, "
                            "actual number of columns = {}".format(
                                expected_col_count, col_count))

        for line in fin:
            cols = line.split("\t")
            if len(cols) != expected_col_count:
                continue
            date = parse_date(cols[0], "%Y.%m.%d")
            _type = cols[1]
            quantity_krw, quantity_sp500 = [
                int(extract_numbers(v)) for v in cols[3:5]
            ]

            log.info(", ".join([c.strip() for c in cols]))

            if not (_type == "일반입금" or _type == "일반신규"):
                log.info("Record type '{}' will be ignored", _type)
                continue

            with Transaction.create() as t:
                # NOTE: The actual deposit date and the buying date generally
                # differ by a few days. Need to figure out how to parse this
                # properly from the raw data.
                try:
                    deposit(account_checking, asset_krw, -quantity_krw, date,
                            t)
                except IntegrityError:
                    log.warn("Identical record exists")
                    db.session.rollback()

                try:
                    deposit(account_sp500, asset_sp500, quantity_sp500, date,
                            t)
                except IntegrityError:
                    log.warn("Identical record exists")
                    db.session.rollback()
Example #32
0
def test_account_net_worth_4(account_checking, asset_usd):
    """Ensures Account.net_worth() works with explicit `created_at`."""
    Record.create(
        account=account_checking, asset=asset_usd, quantity=1000,
        type=RecordType.deposit,
        created_at=parse_datetime('2018-08-30 23:00:00'))

    net_worth = account_checking.net_worth(
        base_asset=asset_usd, evaluated_at=parse_date('2018-08-30'))
    assert net_worth == 1000
Example #33
0
def test_8percent_parse_data():
    sample_file = os.path.join(PROJECT_PATH, 'tests', 'data',
                               '8percent-829.html')
    with open(sample_file) as fin:
        raw = fin.read()

    stored_data = [
        ('2016-04-11', 1694, 613, 160, 340),
        ('2016-05-11', 1916, 390, 90, 0),
        ('2016-06-13', 1920, 386, 90, 0),
        ('2016-07-11', 1982, 324, 80, 0),
        ('2016-08-10', 1963, 343, 80, 0),
        ('2016-09-12', 1979, 327, 80, 0),
        ('2016-10-10', 2005, 301, 70, 0),
        ('2016-11-14', 1992, 314, 70, 0),
        ('2016-12-12', 2054, 252, 60, 0),
        ('2017-01-10', 2044, 262, 60, 0),
        ('2017-02-13', 2053, 253, 60, 0),
        ('2017-03-13', 2099, 207, 50, 0),
        ('2017-04-10', 2101, 205, 50, 0),
        ('2017-05-15', 2098, 208, 50, 0),
        ('2017-06-12', 2145, 161, 40, 0),
        ('2017-07-10', 2151, 155, 30, 0),
        ('2017-08-14', 2153, 153, 30, 0),
        ('2017-09-11', 2188, 118, 20, 0),
        ('2017-10-11', 2198, 108, 20, 0),
        ('2017-11-13', 2216, 90, 20, 0),
        ('2017-12-11', 2238, 68, 10, 0),
        ('2018-01-10', 2251, 55, 10, 0),
        ('2018-02-12', 2270, 36, 0, 0),
        ('2018-03-12', 2290, 16, 0, 0),
    ]

    provider = _8Percent()
    parsed_data = provider.parse_data(raw)

    assert parsed_data['name']
    assert parsed_data['grade']
    assert isinstance(parsed_data['duration'], int)
    assert isinstance(parsed_data['annual_percentage_yield'], float)
    assert 0.0 < parsed_data['annual_percentage_yield'] <= 0.3
    assert isinstance(parsed_data['amount'], int)
    assert 0 < parsed_data['amount']

    flag = True
    for expected, actual in zip(stored_data, parsed_data['records']):
        assert len(expected) == len(actual)
        expected = list(expected)
        expected[0] = parse_date(expected[0])
        for exp, act in zip(expected, actual):
            flag = False
            assert exp == act

    if flag:
        pytest.fail('parse_8percent_data() did not return any data')
Example #34
0
def test_account_net_worth_4(account_checking, asset_usd):
    """Ensures Account.net_worth() works with explicit `created_at`."""
    Record.create(account=account_checking,
                  asset=asset_usd,
                  quantity=1000,
                  type=RecordType.deposit,
                  created_at=parse_datetime('2018-08-30 23:00:00'))

    net_worth = account_checking.net_worth(
        base_asset=asset_usd, evaluated_at=parse_date('2018-08-30'))
    assert net_worth == 1000
Example #35
0
def test_records(account_checking, asset_krw):
    with Transaction.create() as t:
        record = deposit(account_checking, asset_krw, 1000,
                         parse_date('2016-03-14'), t)

        # Make sure the record type has been set implictly
        assert RecordType.deposit == record.type

    with Transaction.create() as t:
        record = deposit(account_checking, asset_krw, -2000,
                         parse_date('2016-03-14'), t)

        # Make sure the record type has been set implictly
        assert RecordType.withdraw == record.type

    with Transaction.create() as t:
        record = balance_adjustment(account_checking, asset_krw, 3000,
                                    parse_date('2016-03-14'), t)

        # Make sure the record type has been set explicitly
        assert RecordType.balance_adjustment == record.type
Example #36
0
def test_yahoo_provider(granularity):
    provider = Yahoo()
    symbol = "MSFT"
    start_time = datetime.combine(parse_date(-5), time(0))
    end_time = datetime.utcnow()
    asset_values = provider.asset_values(symbol, start_time, end_time, granularity)
    flag = False
    for asset_value in asset_values:
        flag = True
        assert len(asset_value) == 6
        assert all([c is not None for c in asset_value])
    assert flag
Example #37
0
def test_portfolio_balance(account_checking, account_savings, account_sp500,
                           asset_krw, asset_sp500):
    portfolio = Portfolio()
    portfolio.base_asset = asset_krw
    portfolio.add_accounts(account_checking, account_savings, account_sp500)

    assert portfolio.balance(parse_date('2016-05-20')) == {}

    Record.create(
        created_at=parse_date('2016-05-01'), account=account_checking,
        asset=asset_krw, quantity=1500)
    Record.create(
        created_at=parse_date('2016-05-01'), account=account_savings,
        asset=asset_krw, quantity=3000)
    Record.create(
        created_at=parse_date('2016-05-01'), account=account_sp500,
        asset=asset_sp500, quantity=120)

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 4500, asset_sp500: 120}

    Record.create(
        created_at=parse_date('2016-05-02'), account=account_savings,
        asset=asset_krw, quantity=4000)
    Record.create(
        created_at=parse_date('2016-05-03'), account=account_savings,
        asset=asset_krw, quantity=5000)

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 13500, asset_sp500: 120}

    Record.create(
        created_at=parse_date('2016-05-04'), account=account_savings,
        asset=asset_krw, quantity=10000, type=RecordType.balance_adjustment)

    assert portfolio.balance(parse_date('2016-05-20')) \
        == {asset_krw: 11500, asset_sp500: 120}

    db.session.delete(portfolio)
    db.session.commit()
Example #38
0
def test_yahoo_provider(granularity):
    provider = Yahoo()
    symbol = 'MSFT'
    start_time = datetime.combine(parse_date(-5), time(0))
    end_time = datetime.utcnow()
    asset_values = \
        provider.asset_values(symbol, start_time, end_time, granularity)
    flag = False
    for asset_value in asset_values:
        flag = True
        assert len(asset_value) == 6
        assert all([c is not None for c in asset_value])
    assert flag
Example #39
0
def test_balance(account_checking, asset_krw, asset_usd):
    assert account_checking.balance() == {}

    deposit(account_checking, asset_krw, 1000, parse_date('2016-05-01'))
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 1000}

    deposit(account_checking, asset_krw, -500, parse_date('2016-05-02'))
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500}

    deposit(account_checking, asset_usd, 25, parse_date('2016-05-03'))
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500, asset_usd: 25}

    balance_adjustment(account_checking, asset_usd, 40,
                       parse_date('2016-05-04'))
    assert account_checking.balance(parse_date('2016-05-19')) \
        == {asset_krw: 500, asset_usd: 40}
Example #40
0
def import_sp500():
    app = create_app(__name__)
    with app.app_context():
        account_checking = Account.get(id=1001)
        account_sp500 = Account.get(id=7001)
        asset_krw = Asset.query.filter_by(name='KRW').first()
        asset_sp500 = Asset.query.filter_by(name='KB S&P500').first()

        with open('sample-data/sp500.csv') as fin:
            for line in fin:
                cols = line.split()
                if len(cols) != 5:
                    continue
                date = parse_date(cols[0], '%Y.%m.%d')
                _type = cols[1]
                quantity_krw, quantity_sp500 = \
                    [int(extract_numbers(v)) for v in cols[2:4]]

                print(cols)

                withdraw = _type == '일반입금'

                with Transaction.create() as t:
                    if withdraw:
                        Record.create(created_at=date,
                                      account=account_checking,
                                      asset=asset_krw,
                                      quantity=-quantity_krw,
                                      transaction=t)
                    Record.create(created_at=date,
                                  account=account_sp500,
                                  asset=asset_sp500,
                                  quantity=quantity_sp500,
                                  transaction=t)

        print(
            account_sp500.net_worth(make_date('2016-02-25'),
                                    target_asset=asset_krw))
Example #41
0
def test_insert_stock_record(db, account_stock, account_checking):
    data = {
        "date": parse_date("2016-06-30"),
        "sequence": 1,
        "category1": "장내매수",
        "category2": "매수",
        "code": "005380",
        "name": "현대차",
        "unit_price": 136000,
        "quantity": 10,
        "subtotal": 1360000,
        "interest": 0,
        "fees": 200,
        "late_fees": 0,
        "channel": "",
        "final_amount": 1670200,
    }
    asset = Asset.create(type="stock", code="005380.KS", description="현대차")
    record = insert_stock_record(data, account_stock, account_checking)

    # TODO: Automate this process
    db.session.delete(record)
    db.session.delete(asset)
    db.session.commit()
Example #42
0
def test_insert_stock_record(db, account_stock, account_checking):
    data = {
        'date': parse_date('2016-06-30'),
        'sequence': 1,
        'category1': '장내매수',
        'category2': '매수',
        'code': '005380',
        'name': '현대차',
        'unit_price': 136000,
        'quantity': 10,
        'subtotal': 1360000,
        'interest': 0,
        'fees': 200,
        'late_fees': 0,
        'channel': '',
        'final_amount': 1670200,
    }
    asset = Asset.create(type='stock', code='005380.KS', description='현대차')
    record = insert_stock_record(data, account_stock, account_checking)

    # TODO: Automate this process
    db.session.delete(record)
    db.session.delete(asset)
    db.session.commit()
Example #43
0
def request_import_stock_values(code):
    """Enqueue a request to import stock values."""
    start_time = date_to_datetime(parse_date(-3))
    end_time = date_to_datetime(parse_date(0))

    request_import_stock_values_(code, start_time, end_time)
Example #44
0
def test_account_net_worth_1(account_checking, asset_krw):
    assert 0 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-01'), base_asset=asset_krw)
    assert 0 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-02'), base_asset=asset_krw)
    assert 0 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-03'), base_asset=asset_krw)
    assert 0 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-04'), base_asset=asset_krw)

    with Transaction.create() as t:
        Record.create(
            created_at=parse_date('2016-01-01'), transaction=t,
            account=account_checking, asset=asset_krw, quantity=1000)

    assert 1000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-01'), base_asset=asset_krw)
    assert 1000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-02'), base_asset=asset_krw)
    assert 1000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-03'), base_asset=asset_krw)
    assert 1000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-04'), base_asset=asset_krw)

    with Transaction.create() as t:
        Record.create(
            created_at=parse_date('2016-01-02'), transaction=t,
            account=account_checking, asset=asset_krw, quantity=2000)

    assert 1000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-01'), base_asset=asset_krw)
    assert 3000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-02'), base_asset=asset_krw)
    assert 3000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-03'), base_asset=asset_krw)
    assert 3000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-04'), base_asset=asset_krw)

    with Transaction.create() as t:
        Record.create(
            created_at=parse_date('2016-01-03'), transaction=t,
            account=account_checking, asset=asset_krw, quantity=-1500)

    assert 1000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-01'), base_asset=asset_krw)
    assert 3000 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-02'), base_asset=asset_krw)
    assert 1500 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-03'), base_asset=asset_krw)
    assert 1500 == account_checking.net_worth(
        evaluated_at=parse_date('2016-01-04'), base_asset=asset_krw)
Example #45
0
def test_portfolio(account_hf, asset_hf1, account_checking, asset_krw):
    portfolio = Portfolio()
    portfolio.base_asset = asset_krw
    portfolio.add_accounts(account_hf, account_checking)

    with Transaction.create() as t:
        Record.create(
            created_at=parse_date('2015-12-04'), transaction=t,
            account=account_checking, asset=asset_krw, quantity=500000)
        Record.create(
            created_at=parse_date('2015-12-04'), transaction=t,
            account=account_checking, asset=asset_krw, quantity=-500000)
        Record.create(
            created_at=parse_date('2015-12-04'), transaction=t,
            account=account_hf, asset=asset_hf1, quantity=1)

    # The net asset value shall not be available at this point
    with pytest.raises(AssetValueUnavailableException):
        net_worth = portfolio.net_worth(evaluated_at=parse_date('2015-12-04'),
                                        granularity=Granularity.day)

    # Initial asset value
    AssetValue.create(
        evaluated_at=parse_date('2015-12-04'), asset=asset_hf1,
        base_asset=asset_krw, granularity=Granularity.day, close=500000)

    net_worth = portfolio.net_worth(evaluated_at=parse_date('2015-12-04'),
                                    granularity=Granularity.day)
    assert 500000 == net_worth

    # 1st payment
    interest, tax, returned = 3923, 740, 30930
    with Transaction.create() as t:
        Record.create(
            created_at=parse_date('2016-01-08'), transaction=t,
            account=account_checking, asset=asset_krw, quantity=returned)
    # Remaining principle value after the 1st payment
    AssetValue.create(
        evaluated_at=parse_date('2016-01-08'), asset=asset_hf1,
        base_asset=asset_krw, granularity=Granularity.day, close=472253)

    net_worth = portfolio.net_worth(evaluated_at=parse_date('2016-01-08'),
                                    granularity=Granularity.day)
    assert 500000 + (interest - tax) == net_worth

    # 2nd payment
    with Transaction.create() as t:
        Record.create(
            created_at=parse_date('2016-02-05'), transaction=t,
            account=account_checking, asset=asset_krw, quantity=25016)
    # Remaining principle value after the 2nd payment
    AssetValue.create(
        evaluated_at=parse_date('2016-02-05'), asset=asset_hf1,
        base_asset=asset_krw, granularity=Granularity.day, close=450195)

    db.session.delete(portfolio)
    db.session.commit()
Example #46
0
def request_import_stock_values(code):
    """Enqueue a request to import stock values."""
    start_time = date_to_datetime(parse_date(-3))
    end_time = date_to_datetime(parse_date(0))

    request_import_stock_values_(code, start_time, end_time)
Example #47
0
 def __set__(self, instance, value):
     self._values[instance] = parse_date(value, self.date_format)