Skip to content

CoinMarketCap rank

Use CoinMarketCap rank with Binance spot OHLC

This example demonstrates how to use multiple data sources.

CoinMarketCap rank for DASH file contains daily CoinMarketCap rank for DASH collected over 2022 year.

import numpy as np
import pandas_ta as ta

from cipher import Cipher, Session, Strategy, quote


class CmcStrategy(Strategy):
    def compose(self):
        df = self.datas.df
        cmc_df = self.datas[1]

        df = df.join(cmc_df)
        df["rank"] = df["cmc_rank"].fillna(method="ffill")
        df["rank_ema21"] = ta.ema(df["rank"], length=21)
        df["rank_ema7"] = ta.ema(df["rank"], length=7)

        df["difference"] = df["rank_ema7"] - df["rank_ema21"]
        df["entry"] = np.sign(df["difference"].shift(1)) != np.sign(df["difference"])

        df["cross_up"] = df["entry"] & (df["difference"] > 0)
        df["cross_down"] = df["entry"] & (df["difference"] < 0)

        return df

    def on_entry(self, row: dict, session: Session):
        if row["cross_down"]:
            # buy dash worth 100 USD
            session.position += quote(100)
        else:
            session.position -= quote(100)

    def on_cross_up(self, row, session: Session):
        """Cross up is bearish, because the lower rank - the better."""
        if session.is_long:
            session.position = 0

    def on_cross_down(self, row, session: Session):
        if not session.is_long:
            session.position = 0

    def on_stop(self, row: dict, session: Session):
        session.position = 0


def main():
    cipher = Cipher()
    cipher.add_source("binance_spot_ohlc", symbol="DASHUSDT", interval="1d")
    cipher.add_source("csv_file", path="data/131_dash.csv")
    cipher.set_strategy(CmcStrategy())
    cipher.run(start_ts="2022-01-01", stop_ts="2022-12-31")
    print(cipher.sessions)
    print(cipher.stats)
    cipher.plot(
        rows=[
            ["ohlc"],
            ["signals"],
            ["rank", "rank_ema21", "rank_ema7"],
            ["balance"],
        ]
    )


if __name__ == "__main__":
    main()

Output:

python cmc.py
Session                 Period           PnL
----------------------  --------  ----------
short 2022-01-21 00:00  24d         1.79754
long 2022-02-14 00:00   10d       -15.4143
short 2022-02-24 00:00  3d         -0.455581
long 2022-02-27 00:00   1d         13.9456
short 2022-02-28 00:00  1d          0.39801
long 2022-03-01 00:00   2d         -3.2967
short 2022-03-03 00:00  7d         -8.05785
long 2022-03-10 00:00   24d        26.7686
short 2022-04-03 00:00  36d        47.2851
long 2022-05-09 00:00   49d       -29.7568
short 2022-06-27 00:00  32d        -3.05499
long 2022-07-29 00:00   1d          0.197628
short 2022-07-30 00:00  12d        -9.66469
long 2022-08-11 00:00   4d         -4.31655
short 2022-08-15 00:00  4d         15.7895
long 2022-08-19 00:00   3d          5.58036
short 2022-08-22 00:00  1d         -2.537
long 2022-08-23 00:00   19d        -0.412371
short 2022-09-11 00:00  20d        13.6025
long 2022-10-01 00:00   18d        -4.86461
short 2022-10-19 00:00  24d        14.8615
long 2022-11-12 00:00   6d          2.04142
short 2022-11-18 00:00  1d         -3.21832
long 2022-11-19 00:00   41d        17.9494
----------------  ---------------------  -----
start             2022-01-21 00:00
stop              2022-12-30 00:00
period            343d
trades            24
longs             12                     50.0%
shorts            12                     50.0%
period median     8d 12h
period max        49d
success           12                     50.0%
success median    13.774031351671103224
success max       47.285067873303167421
success row       2
failure           12                     50.0%
failure median    3.806625029646612380
failure max       29.756795422031473533
failure row       2
spf               1.0
pnl               75.167382902613042311
commission        0E-18
balance min       -21.503915296725822
balance max       94.57749526216361
balance drawdown  51.459489382273404
romad             1.4607098477838074
----------------  ---------------------  -----

CMC Dash plot

Run the strategy for multiple assets and write stats to a csv file

import csv
import json

import numpy as np
import pandas_ta as ta

from cipher import Cipher, Session, Strategy, quote


class CmcStrategy(Strategy):
    def compose(self):
        df = self.datas.df

        # close price is required
        df["close"] = df["price"]
        df["rank"] = df["cmc_rank"].fillna(method="ffill")
        df = df.drop(columns=["price", "cmc_rank"])

        df["rank_ema21"] = ta.ema(df["rank"], length=21)
        df["rank_ema7"] = ta.ema(df["rank"], length=7)

        df["difference"] = df["rank_ema7"] - df["rank_ema21"]
        df["entry"] = np.sign(df["difference"].shift(1)) != np.sign(df["difference"])

        df["cross_up"] = df["entry"] & (df["difference"] > 0)
        df["cross_down"] = df["entry"] & (df["difference"] < 0)

        return df

    def on_entry(self, row: dict, session: Session):
        if row["cross_down"]:
            session.position += quote(100)
        else:
            session.position -= quote(100)

    def on_cross_up(self, row, session: Session):
        if session.is_long:
            session.position = 0

    def on_cross_down(self, row, session: Session):
        if not session.is_long:
            session.position = 0


def run_for_asset(asset_id, asset_slug):
    cipher = Cipher()
    cipher.add_source("csv_file", path=f"data/{asset_id}_{asset_slug}.csv")
    cipher.set_strategy(CmcStrategy())
    cipher.run(start_ts="2021-11-20", stop_ts="2022-01-20")
    cipher.set_commission("0.00075")
    return cipher.stats


def main():
    with open("data/cmc_results.csv", "w") as fo:
        writer = csv.writer(fo)
        writer.writerow(["slug", "sessions", "pnl", "drawdown"])
        with open("data/ids.json", "r") as f:
            data = json.load(f)
            for i, slug, symbol, name in data["data"]:
                stats = run_for_asset(i, slug)
                writer.writerow(
                    [slug, stats.sessions_n, stats.pnl, stats.balance_drawdown_max]
                )


if __name__ == "__main__":
    main()

Stats:

import pandas as pd


pd.set_option("display.float_format", lambda x: '%.3f' % x)

df = pd.read_csv("data/cmc_results.csv")

print(df[df.pnl > 10000])
#                slug  trades         pnl  drawdown
# 2793  uberstate-inc       6 2626781.549    27.372

print(df[df.pnl < -10000])
#                   slug  trades           pnl     drawdown
# 456              aeron       4    -10656.038    10655.839
# 1136          hyperion       1   -155835.789   155855.572
# 1198       fidex-token      15    -20737.524    28933.483
# 1619           onlexpa       2    -43243.517    43257.982
# 2117    kimchi-finance       4    -31278.215    31277.971
# 5422  galaxygoggle-dao       2    -14924.211    15785.439
# 5493           pumpeth       4 -79166174.958 93672953.625

df = df[(df.pnl != 0) & (df.pnl > -200) & (df.pnl < 200)]

df["pnl"].describe()
# count   3638.000
# mean     -21.617
# std       46.315
# min     -199.955
# 25%      -41.490
# 50%      -13.245
# 75%        2.371
# max      180.636
# Name: pnl, dtype: float64

df["pnl"].sum()
# -78641.39720448424

Long only, with brackets

import csv
import json

import numpy as np
import pandas_ta as ta

from cipher import Cipher, Session, Strategy, percent, quote


class CmcStrategy(Strategy):
    def compose(self):
        df = self.datas.df

        df["close"] = df["price"]
        # high and low is required for brackets
        df["high"] = df["price"]
        df["low"] = df["price"]
        df["rank"] = df["cmc_rank"].fillna(method="ffill")
        df = df.drop(columns=["price", "cmc_rank"])

        df["rank_ema21"] = ta.ema(df["rank"], length=21)
        df["rank_ema7"] = ta.ema(df["rank"], length=7)

        difference = df["rank_ema7"] - df["rank_ema21"]
        cross = np.sign(difference.shift(1)) != np.sign(difference)

        df["entry"] = cross & (difference < 0)
        df["exit"] = cross & (difference > 0)

        return df

    def on_entry(self, row: dict, session: Session):
        session.position += quote(100)
        session.take_profit = percent(100)
        session.stop_loss = percent(-50)

    def on_exit(self, row, session: Session):
        session.position = 0


def run_for_asset(asset_id, asset_slug):
    cipher = Cipher()
    cipher.add_source("csv_file", path=f"data/{asset_id}_{asset_slug}.csv")
    cipher.set_strategy(CmcStrategy())
    cipher.run(start_ts="2021-11-20", stop_ts="2022-01-20")
    cipher.set_commission("0.00075")
    return cipher.stats


def main():
    with open("data/cmc_results.csv", "w") as fo:
        writer = csv.writer(fo)
        writer.writerow(["slug", "sessions", "pnl", "drawdown"])
        with open("data/ids.json", "r") as f:
            data = json.load(f)
            for i, slug, symbol, name in data["data"]:
                stats = run_for_asset(i, slug)
                writer.writerow(
                    [slug, stats.sessions_n, stats.pnl, stats.balance_drawdown_max]
                )


if __name__ == "__main__":
    main()

Output:

count   3488.000
mean     -12.328
std       37.868
min     -241.161
25%      -28.682
50%      -12.201
75%       -1.477
max      198.500

Sum: -43001