def _to_returns(cls, augmented: pd.DataFrame) -> Dict[str, Optional[float]]:
     returns = dict()
     lookbacks = properties.get("fund.lookbacks")
     dt = augmented.last_valid_index()
     for lookback in lookbacks:
         window = augmented[dt - pd_offset_from_lookback(lookback): dt]["value"]
         returns[lookback] = (window.iat[-1] - window.iat[0]) / window.iat[0] \
             if len(window.index) \
             else None
     return returns
Esempio n. 2
0
def get_all_indicators() -> List[Indicator]:
    from .ppo import PPO
    from .mdd import MDD
    from .num_breakouts import NumBreakouts
    from .sharpe_ratio import SharpeRatio
    from .stability import Stability
    from .returns import MaxReturns, MinReturns
    from .rsi import RSI
    lookbacks = properties.get("fund.lookbacks")
    return [MDD(), MDT(), NumBreakouts(), PPO(), RSI(), SharpeRatio(), Stability()] \
           + [MaxReturns(lookback) for lookback in lookbacks] \
           + [MinReturns(lookback) for lookback in lookbacks]
Esempio n. 3
0
def calc_fees(funds: List[Fund]) -> pd.DataFrame:
    platform_charge = properties.get("fund.fees.platform.charge")
    fees = pd.DataFrame(
        [[fund.ocf, fund.amc, fund.entryCharge, fund.exitCharge, fund.bidAskSpread, platform_charge,
          sum(filter(None, [fund.entryCharge, fund.exitCharge, fund.bidAskSpread])),
          sum(filter(None, [fund.ocf, platform_charge]))] for fund in funds],
        index=[fund.isin for fund in funds],
        columns=["ocf", "amc", "entry_charge", "exit_charge", "bid_ask_spread", "platform_charge",
                 "total_one_off_fees",
                 "total_annual_fees"]
    )
    return fees
Esempio n. 4
0
def test_get_from_environment():
    sys_path = properties.get("PATH")
    assert isinstance(sys_path, str)
    assert sys_path
Esempio n. 5
0
def test_get_missing_property():
    assert properties.get("missing.property") is None
Esempio n. 6
0
def test_parse_json():
    assert properties.get("fund.fees.platform.charge") == 0.0035
    assert properties.get("fund.lookbacks") == [
        "5Y", "3Y", "1Y", "6M", "3M", "1M", "2W", "1W", "3D", "1D"]
Esempio n. 7
0
def test_get_from_file():
    assert properties.get("heroku.app.name") == "fund-analyzer-compute"
Esempio n. 8
0
import falcon
from waitress import serve

from lib.util import properties
from server.middleware.logging import LoggingMiddleware
from server.routes.home_routes import home_routes
from server.routes.indicators_routes import indicators_routes
from server.routes.simulate_routes import simulate_routes

app = falcon.API(middleware=[LoggingMiddleware()])

app.add_route("/", home_routes)
app.add_route("/indicators/fund", indicators_routes, suffix="fund")
app.add_route("/indicators/stock", indicators_routes, suffix="stock")
app.add_route("/simulate", simulate_routes)
app.add_route("/simulate/predict", simulate_routes, suffix="predict")
app.add_route("/simulate/strategies", simulate_routes, suffix="strategies")

if __name__ == "__main__":
    serve(app, port=properties.get("server.default.port"))
Esempio n. 9
0
from datetime import date
from typing import Callable, List, Optional

import pandas as pd
from ffn import calc_sharpe
from pandas.tseries.frequencies import to_offset

from lib.fund.fund import Fund
from lib.util import properties

DAILY_PLATFORM_FEES = (1 + properties.get("fund.fees.platform.charge")) ** (1 / 252) - 1


def calc_returns(prices_df: pd.DataFrame, dt: date, duration: pd.DateOffset, fees_df: pd.DataFrame) -> pd.Series:
    window = prices_df[dt - duration: dt]  # type: ignore
    returns_before_fees = (window.iloc[-1] - window.iloc[0]) / window.iloc[0] if len(window) else 0

    num_bdays = len(window.index) - 1
    prorated_annual_fees = (1 + fees_df["total_annual_fees"]) ** (num_bdays / 252) - 1
    prorated_total_fees = fees_df["total_one_off_fees"] + prorated_annual_fees

    returns_after_fees = returns_before_fees - prorated_total_fees
    return returns_after_fees


def calc_fees(funds: List[Fund]) -> pd.DataFrame:
    platform_charge = properties.get("fund.fees.platform.charge")
    fees = pd.DataFrame(
        [[fund.ocf, fund.amc, fund.entryCharge, fund.exitCharge, fund.bidAskSpread, platform_charge,
          sum(filter(None, [fund.entryCharge, fund.exitCharge, fund.bidAskSpread])),
          sum(filter(None, [fund.ocf, platform_charge]))] for fund in funds],
Esempio n. 10
0
from typing import Dict, Iterator, Optional

import requests
import ujson

from lib.util import properties

DATA_HOST = properties.get("client.data")


def _remove_leading_slash(endpoint: str) -> str:
    return endpoint[1:] if endpoint.startswith("/") else endpoint


def get(endpoint: str, params: Optional[Dict[str, str]] = None) -> object:
    endpoint = f"{DATA_HOST}/{_remove_leading_slash(endpoint)}"
    return requests.get(endpoint, params).json()


def post(endpoint: str, data: Optional[object] = None) -> object:
    endpoint = f"{DATA_HOST}/{_remove_leading_slash(endpoint)}"
    return requests.post(endpoint, json=data)


def stream(endpoint: str, data: Optional[object] = None) -> Iterator[Dict]:
    endpoint = f"{DATA_HOST}/{_remove_leading_slash(endpoint)}"
    line_seps = {b",", b"[", b"]"}
    lines = requests.post(endpoint, json=data, stream=True).iter_lines()
    return (ujson.loads(line)
            for line in lines
            if line not in line_seps)
Esempio n. 11
0
}, {
    "date": "2017-04-26T00:00:00Z",
    "price": 482.0
}, {
    "date": "2017-04-30T00:00:00Z",
    "price": 482.0
}, {
    "date": "2017-05-01T00:00:00Z",
    "price": 482.0
}, {
    "date": "2017-05-02T00:00:00Z",
    "price": 482.0
}])


@pytest.mark.parametrize("lookback", properties.get("fund.lookbacks"))
def test_empty_returns_nan(lookback: str):
    assert np.isnan(
        MinReturns(lookback).calc(historic_prices=pd.Series()).value)
    assert np.isnan(
        MaxReturns(lookback).calc(historic_prices=pd.Series()).value)


@pytest.mark.parametrize("lookback,expected_max,expected_min", [
    ("1D", 0.01, -0.02),
    ("3D", 0.02, -0.03),
    ("1W", 0.03, -0.04),
    ("2W", 0.04, -0.04),
    ("1M", 0.02, -0.02),
    ("3M", np.nan, np.nan),
    ("6M", np.nan, np.nan),