"""tradefloor quickstart, as one script.

Written by the documentation build from the Quickstart page at
https://docs.tradefloor.dev/, for tradefloor 0.8.7 and its default
preset, pt-v20. Every code block on the page is here, in order, and
they share one session. The comments after a block show what it prints.

    pip install "tradefloor==0.8.7"
    python quickstart.py
"""

# Install ------------------------------------------------------------------
import tradefloor as tf

print(tf.__version__, tf.preset_record()["preset"])
# Prints:
#   0.8.7 pt-v20

# Run a small market -------------------------------------------------------
import struct

universe = tf.Universe.random(5, seed=11)       # five made-up companies
engine = tf.Engine(seed=42, universe=universe)  # a market on the default preset
engine.run_days(20)                             # run it for 20 trading days

bars = engine.bars(grain="day")                 # one row per company per day
print(bars.num_rows, "daily bars:", ", ".join(bars.columns))

closes = struct.unpack("<5d", engine.prices())  # each company's price now
for company, close in zip(universe, closes):
    print(f"{company.ticker}  {company.sector:<22} "
          f"{company.initial_price:7.2f} -> {close:7.2f}")
# Prints:
#   100 daily bars: day, bar, instrument_id, open, high, low, close, volume
#   AAA  technology              135.37 ->  133.98
#   AAB  financial_services      282.62 ->  290.24
#   AAC  healthcare               28.59 ->   29.34
#   AAD  energy                   12.73 ->   13.42
#   AAE  consumer_discretionary   31.22 ->   32.41

# Score a simple agent -----------------------------------------------------
class EqualWeight:
    """Put about 100,000 into each company at the first step, then hold."""

    def act(self, obs):
        if obs.step == 0:
            return {ticker: int(100_000 / price)      # a number of shares
                    for ticker, price in zip(obs.tickers, obs.prices)}
        return None                                  # hold


scores = tf.evaluate({"equal": EqualWeight()},
                     seed=42, universe=universe, days=20)
print(scores["equal"])
# Prints:
#   Scorecard('equal', pnl=13,036, return=+1.30%, trades=5, impact=+0.38bps, sharpe=+1.62, vol=10.4%, in_market=100%, exposure=0.51x)

# Understand the result ----------------------------------------------------
scores = tf.evaluate({"equal": EqualWeight(),
                      "buy_and_hold": tf.baselines.BuyAndHold()},
                     seed=42, universe=universe, days=20)
print(scores["buy_and_hold"])
print({name: round(gap) for name, gap in tf.versus_buy_and_hold(scores).items()})
# Prints:
#   Scorecard('buy_and_hold', pnl=23,765, return=+2.38%, trades=5, impact=+0.43bps, sharpe=+1.63, vol=19.3%, in_market=100%, exposure=0.94x)
#   {'equal': -10729}
