Skip to content

Tutorial: Smart Executor Strategy

We will create an trading application in this tutorial, which takes in simple commands from python API to adjust account risk. Use Python to generate signal and use Smart Executor to execute orders.

Steps to create an smart executor strategy


To create a flexible strategy, you will need do the following:

  1. Decide which exchange to trade.
  2. Add the symbols you plan to trade or listen for market data.
  3. Add price models.
  4. Add variables to generate signals.
  5. Add models.
  6. Add strategies.
  7. Create python script to generate signal and sending commands. see more details -> smart_executor reference

Configure

We use a json file to configure the trading applications. The file contains information about api keys, log path, and strategy components. Please update the API key information in the example configuration below:

{
    "instance": {
        "license_id":"apifiny001",
        "license_key":"apifiny123456",
        "log_path": "./logs/strategy_demo",
        "name": "strategy_demo"
    },
    "ib_gateway": {
        "ip": "127.0.0.1",
        "port": 4002
    },
    "servers": {
        "redis_server": "127.0.0.1"
    },
    "apikeys": {
        "BINANCE": {
            "key": "",
            "secret": ""
            },
        "BINANCEUS": {
            "key": "",
            "secret": ""
            },
        "OKEX": {
            "key": "",
            "secret": "",
            "pass": ""
            }       
    },
    "fees": {
        "BINANCE": {
            "make": 0.0,
            "take": 0.00045
        },
        "BINANCEUS": {
            "make": 0.0,
            "take": 0.000462
        },      
        "OKEX": {
            "make": 0.0,
            "take": 0.0002
        }
    },   
    "exchanges":
    [
        {"exchange":"BINANCEUS","trade_type":"Direct","market_data_type":"Direct"}
    ],
    "risk_formulas": [
        ["Port_Risk", ["RiskFormula", {"components": [[["BTCUSDT", "BINANCEUS"], 1.0]]}]]
    ],
    "accounts": [
        [10001, ["Account", {"risk_formulas": ["Port_Risk"], "id": 10001}]]
    ],
    "symbols": [
        {"port": ["BTCUSDT", "BINANCEUS"], "cid": 10000}
    ],
    "symbol_info": {
        "BTCUSDT.BINANCEUS": {"ticksize": 0.01, "lotsize": 0.0001, "price_precision": 2.0, "min_order_size": 0.0001, "qty_precision": 6.0, "multiple": 1.0}
    },
    "players": [
        ["BTCUSDT.HUOBI_Player", ["CobJsonPlayer", {"port": ["BTCUSDT", "BINANCEUS"], "path": "/data/cc/prod/ccc_record_2"}]]
    ],
    "samplers": [
        ["ts_basis", ["TimeSampler", {"halflife": 1, "msecs": 100}]]
    ],
    "pricing_models": [
        ["BTCUSDT.HUOBI_midpx", ["MidPx", {"port": ["BTCUSDT", "BINANCEUS"]}]], 
        ["BTCUSDT.HUOBI_Vwap", ["Vwap", {"port": ["BTCUSDT", "BINANCEUS"], "sampler": "ts_basis"}]]
    ],
    "variables": [
        ["Zero", ["Const", {"value": 0.0}]]
    ],
    "models": [
        ["Zero_m", ["LinearModel", {"variable": "Zero"}]]
    ],
    "strategies": [
        ["BTCUSDT.BINANCEUS", ["CCEventMakerStrategy", {"symbol": "BTCUSDT", "trade_market": "BINANCEUS", "account": 10001, "dep_pm": "BTCUSDT.HUOBI_midpx", "model": "Zero_m", "VWap": "BTCUSDT.HUOBI_Vwap", "max_spread_bps": 5, "max_quote_frombbo_bps": 0.001, "update_quote_bps": 2, "quote_bps": 3, "allowed_bps": 5, "order_notional": 500, "max_notional": 2500, "max_risk": 2500, "cooloff": 100, "start_time": "00:30:00", "end_time": "23:59:59", "use_separate_logs": true, "close_mode": "none"}]]
    ]
}

Python Script

To create a functional python script, you will need following parts:

  1. Get data and process with your algorithim. We provide CCxtMarketData in the example as a simple way getting raw data.
  2. Use our ExecutorApi to send commands to our smart executor.

CCxtMarketData

Field Description Mandatory
exchange The exchange you need data from. Yes
symbol_coin The symbol coin you need data. Yes
symbol_basecoin The basecoin of the symbol you need data. Yes
Function Parameters Mandatory
get_price NA Yes
get_ema sample time interval, halflife Yes
get_candle_data sample time interval Yes

ExecutorApi

Field Description Mandatory
exchange The exchange you need data from. Yes
symbol_coin The symbol coin you need data. Yes
symbol_basecoin The basecoin of the symbol you need data. Yes

Commands

Function Description Parameters
send_cmd_maker Send position change you want, accumulate on smart executor side, and execute by making order. instance name, trading direction, target position level
send_cmd_taker Send the position level you want, calculate order quantity on smart executor side, and execute by taking order. instance name, target position level

You only need to send position increase/decrease commands by send_cmd_maker, Smart Executor will automatically summarize all your command and execute;

Example

from apifiny.smart.ExecutorApi import ExecutorApi as ea
from apifiny.smart.examples.CcxtMarketData import CcxtMarketData as md

def strategy_live_demo(exchange, symbol_coin,symbol_basecoin,instance,targetLevel,interval,thresh,totalLevel):
    commander = ea(exchange,symbol_coin,symbol_basecoin)
    data= md(exchange, symbol_coin,symbol_basecoin)
    count = 0
    while True:
        try: 
            data.get_price()
            #test.get_candle_data("1m") #1m, 5m, 1h, 1d #By default you will have 500 metrics (if available)
            data_long = data.get_ema("1m",5) 
            data_short = data.get_ema("1m",1) 
            ema_long = data_long['Close'][data_long['Close'].size-1]
            ema_short = data_short['Close'][data_short['Close'].size-1]
        except:
            print("lost connection from ccxt")
            time.sleep(interval)
            continue
        if ema_long < ema_short and totalLevel < 1:
            if totalLevel < 0 and (abs(ema_long - ema_short)/data.mid) > thresh*0.0001:
                print("thresh check: ",{(ema_long - ema_short)/data.mid}, " total level: ", totalLevel)
                print("buy back: ema_long: ",{ema_long}, " ema_short: ", {ema_short}, "thresh", {thresh})
                commander.send_cmd_maker(instance, "buy", targetLevel)
                count += 1
                totalLevel += targetLevel
            elif totalLevel >= 0 and (abs(ema_long - ema_short)/data.mid) > thresh*(1+totalLevel/targetLevel)*0.0001:
                print("thresh check: ",{(ema_long - ema_short)/data.mid}, " total level: ", totalLevel)
                print("buy more: ema_long: ",{ema_long}, " ema_short: ", {ema_short}, "thresh", {thresh*(1+abs(totalLevel)/targetLevel)*0.0001})
                commander.send_cmd_maker(instance, "buy", targetLevel)
                count += 1
                totalLevel += targetLevel

        elif ema_long > ema_short and totalLevel > -1:
            if totalLevel <= 0 and (abs(ema_long - ema_short)/data.mid) > thresh*(1+abs(totalLevel)/targetLevel)*0.0001:
                print("thresh check: ",{(ema_long - ema_short)/data.mid}, " total level: ", totalLevel)
                print("sell more: ema_long: ",{ema_long}, " ema_short: ", {ema_short}, "thresh", {thresh*(1+abs(totalLevel)/targetLevel)*0.0001})
                commander.send_cmd_maker(instance, "sell", targetLevel)
                count += 1
                totalLevel -= targetLevel
            elif totalLevel > 0 and (abs(ema_long - ema_short)/data.mid) > thresh*0.0001:
                print("thresh check: ",{(ema_long - ema_short)/data.mid}, " total level: ", totalLevel)
                print("sell back: ema_long: ",{ema_long}, " ema_short: ", {ema_short}, "thresh", {thresh})
                commander.send_cmd_maker(instance, "sell", targetLevel)
                count += 1
                totalLevel -= targetLevel

        time.sleep(interval)