3.1 Use Websocket

For JavaScript:

function main() {
    LogStatus("connecting...");
    var client = Dial("wss://stream.binance.com:9443/ws/!ticker@arr");
    if (!client) {
        Log("Connection failed, program exited");
        return
    }
    Log("The connection is successful and the disconnected line is automatically reconnected")
    while (true) {
        var buf = client.read() // Read only returns data obtained after calling read
        if (!buf) {
            break;
        }
        var table = {
            type: 'table',
            title: 'Quotes chart',
            cols: ['Currency', 'highest', 'lowest', 'Bid', 'Ask', ' Last traded price', 'volume', 'Update time'],
            rows: [],
        };
        var obj = JSON.parse(buf);
        _.each(obj, function(ticker) {
            table.rows.push([ticker.s, ticker.h, ticker.l, ticker.b, ticker.a, ticker.c, ticker.q, _D(ticker.E)])
        });
        LogStatus('`' + JSON.stringify(table) + '`')
    }
    client.close();
}

For Python, you can use Dial() function as well, or websocket_client library to access websocket.

3.2 Use C++

There are some difference between C++ and JavaScript in writing strategy.

void main() {
    if (!Test("c++")) {
        Panic("please download the lastest docker");
    }
    // json: https://github.com/nlohmann/json
    // using Valid to judge return object is null or not.
    LogProfitReset();
    LogReset();
    Log(_N(9.12345, 2));
    Log("use _C", _C(exchange.GetTicker), _C(exchange.GetAccount));

    // test async
    auto routineTicker = exchange.Go("GetTicker");
    auto routineDepth = exchange.Go("GetDepth");
    Ticker asyncTicker;
    Depth asyncDepth;

    // No timeout, wait until Ticker is returned
    if (routineTicker.wait(asyncTicker)) {
        Log("Wait Ticker OK", asyncTicker.Valid, asyncTicker, asyncTicker.Last);
    } else {
        Log("Wait Ticker fail");
    }
    // With 300ms tiemout, 0 means return immediately.
    if (routineDepth.wait(asyncDepth, 200)) {
        // not sure the depth returned is valid, use asyncDepth.Valid.
        Log("Wait Depth OK", asyncDepth.Valid, asyncDepth);
    } else {
        Log("Wait Depth timeout");
    }

    auto records = _C(exchange.GetRecords);
    Log("Last Kline", records[records.size()-1].Time, _D(records[records.size()-1].Time), records[records.size()-1]);
    // Test TA
    auto ema = TA.EMA(records, 20);
    Log("EMA", ema[ema.size()-1], ema[ema.size()-2], ema[ema.size()-3]);

    auto macd = talib.MACD(records);
    Log("MACD", macd[0][macd[0].size()-1], macd[1][macd[1].size()-1], macd[2][macd[2].size()-1]);

    //SetErrorFilter("timeout");
    Log(GetOS(), GetPid(), GetLastError(), "MD5", MD5("hello"));
    Log("Hash", Hash("md5", "hex", "hello"), Hash("sha512", "base64", "hello"));
    Log("HMAC", HMAC("sha512", "base64", "hello", "pass"));
    Log(Version(), Unix(), UnixNano());
    Log("Start Test Chart");
    Chart c = Chart(R"EOF({"chart":{"type":"line"},"title":{"text":"Simple Chart"},"xAxis":{"title":{"text":"Date"}},"yAxis":{"title":{"text":"Number"}},"series":[{"name":"number","data":[]}]})EOF");
    c.reset();
    for (size_t i = 0; i < 10; i++) {
        c.add(0, {(Unix() + i)*1000, rand() % 100});
    }
    Log(exchange.GetName(), exchange.GetLabel(), exchanges.size());
    auto acc = exchange.GetAccount();
    if (acc.Valid) {
        Log(acc);
    }

    // Using LogStatus and json draw a table, learn more about json libray: https://github.com/nlohmann/json
    json tbl = R"({"type" : "table", "title" : "AAA", "cols" : ["Head1", "Head2"], "rows": []})"_json;
    tbl["rows"].push_back({"111", "222"});
    tbl["rows"].push_back({"col2", "col22"});
    LogStatus("`"+tbl.dump()+"`");

    auto ticker = exchange.GetTicker();
    if (ticker.Valid) {
        Log(ticker);
        Log(ticker.Info); // Info Struct is json object
    }

    auto d = exchange.GetDepth();
    if (d.Valid) {
        Log(d.Asks[0], d.Bids[0]);
    }
    // Test features
    if (exchange.GetName() == "Futures_OKCoin") {
        exchange.SetContractType("this_week");
        exchange.SetMarginLevel(20);
        exchange.SetDirection("closebuy");

        auto positions = exchange.GetPosition();
        if (positions.Valid) {
            Log(positions);
        }
    }
    // test other function
    Log("HttpQuery", HttpQuery("http://www.baidu.com/404").size());
    auto obj = json::parse(HttpQuery("http://www.baidu.com/404", "", "", "", true));
    string body = obj["Body"];
    Log("HttpQuery", body.size(), obj["Header"].dump());
    Log(Mail("smtp://smtp.163.com", "test@163.com", "password", "admin@163.com", "title", "test c++ email"));
    // Test Dial
    auto client = Dial("tcp://www.baidu.com:80");
    if (client.Valid) {
        client.write("GET / HTTP/1.1\nHost: www.baidu.com\nConnection: Close\n\n");
        while (true) {
            string buf = client.read();
            if (buf == "") {
                break;
            }
            Log("Dial receive", buf.size());
        }
        client.close();
    }

    _G("OK","xxx");
    Log(_G("OK"));
    _G("OK","yyyyyy");
    Log(_G("OK"));
    _G("OK",NULL);
    Log(_G("OK"));
}

3.3 Sell ALL AltCoin to BTC in Binance

This strategy will sell all your AltCoin to BTC (or ETH, BNB, USDT), learn how to trade multiple trading pair, and follow the price and amount filter of exchange.

function main() {
    var quoteCurrency = 'BTC'; //Can be 'ETH', 'BNB', 'USDT'
    Log("Quote Currency", quoteCurrency);
    var symbols = JSON.parse(_C(HttpQuery, "https://api.binance.com/api/v1/exchangeInfo")).symbols;
    _.each(_C(exchange.GetAccount).Info.balances, function(ele) {
        if (ele.asset == quoteCurrency) {
            return
        }
        var totalV = parseFloat(ele.free) + parseFloat(ele.locked);
        if (totalV == 0) {
            return;
        }
        var cfg = _.findWhere(symbols, {symbol: ele.asset+quoteCurrency});
        if (!cfg) {
            Log("Not found", ele.asset, "trading pair", ele);
            return;
        }
        var filter = _.findWhere(cfg.filters, {filterType: "LOT_SIZE"});
        if (!filter) {
            return;
        }

        var v = _N(parseInt(totalV/filter.stepSize)*filter.stepSize, cfg.baseAssetPrecision);
        if (v > 0) {
            Log(ele, "stepSize", filter.stepSize);
            exchange.IO("currency", ele.asset + "_"+quoteCurrency);
            while (true) {
                var orders = _C(exchange.GetOrders);
                _.each(orders, function(order) {
                    exchange.CancelOrder(order.Id);
                });
                if (orders.length == 0) {
                    break;
                }
            }
            exchange.Sell(-1, v);
            Log(ele);
        }
    });
    Log("Done, Now", quoteCurrency, "Balance", _C(exchange.GetAccount).Balance);
}

3.4 Moving Average Strategy

The moving average (MA) is a simple technical analysis tool that smooths out price data by creating a constantly updated average price.

Check on https://www.fmz.com/strategy/103070 for parameters configs.The global variables FastPeriod, SlowPeriod,etc… are defined in configs.

Source code:

function main() {
var initAccount = _C(exchange.GetAccount);//using _C() to retry
var ticker = exchange.GetTicker();
//calc InitValue to log profit
var InitValue = (initAccount.Stocks + initAccount.FrozenStocks)*ticker.Last \
                + initAccount.Balance + initAccount.FrozenBalance;
while (true) {
    var records = _C(exchange.GetRecords);
    ticker =_C(exchange.GetTicker);
    var FastRecords = TA.MA(records,FastPeriod);// using MA of TA-Lib
    var SlowRecords = TA.MA(records,SlowPeriod);
    var NowAccount = _C(exchange.GetAccount);
    var n = _Cross(FastRecords, SlowRecords);// using _Cross(), check on global function
    if (n >= EnterPeriod && NowAccount.Balance > 0) {
        var Price = _N(ticker.Sell+Slippage, 2); // add Slippage to make sure order can be done
        var Amount = _N(0.99*NowAccount.Balance/Price, 3);
        if(Amount>0.1){
           var id = exchange.Buy(Price, Amount);
           //Cancel the pending order
           if(exchange.GetOrders(id).Status == ORDER_STATE_PENDING){exchange.CancelOrder(id);}
           LogProfit((NowAccount.Stocks + NowAccount.FrozenStocks)*ticker.Last\
                     + NowAccount.Balance + NowAccount.FrozenBalance - InitValue);
        }
    }
    if(n <= -EnterPeriod && NowAccount.Stocks > 0) {
        var Price = _N(ticker.Buy-Slippage, 2);
        var Amount = _N(NowAccount.Stocks, 3);
        if(Amount>0.1){
            var id = exchange.Sell(Price, Amount);
            if(exchange.GetOrders(id).Status == ORDER_STATE_PENDING){exchange.CancelOrder(id);}
            LogProfit((NowAccount.Stocks + NowAccount.FrozenStocks)*ticker.Last\
                     + NowAccount.Balance + NowAccount.FrozenBalance - InitValue);
        }
    }
    Sleep(Interval*1000);
}

}

3.5 Iceberg Buy Order

Check on https://www.fmz.com/strategy/103319.

Source code:

var floatAmountBuy = 20
var floatAmountSell = 20
var diffPrice = 3
var Interval = 3000

function CancelPendingOrders() {
    var orders = _C(exchange.GetOrders);
    for (var j = 0; j < orders.length; j++) {
        exchange.CancelOrder(orders[j].Id, orders[j])
    }
}

function GetPrice(depth) {
    var price = {buy:0, sell:0}
    var askAmount = 0
    var bidAmount = 0
    for(var i=0; i<depth.Bids.length; i++){
        askAmount += depth.Asks[i].Amount
        bidAmount += depth.Bids[i].Amount
        if(askAmount >= floatAmountBuy && !price.buy){
            price.buy = depth.Asks[i].Price
        }
        if(bidAmount >= floatAmountSell && !price.sell){
            price.sell = depth.Bids[i].Price
        }
    }
    if(!price.buy || !price.sell){
        price = {buy:depth.Asks[depth.Asks.length-1].Price, sell:depth.Bids[depth.Bids.length-1].Price}
    }
    return price
}

function onTick() {
    var price = GetPrice(_C(exchange.GetDepth))
    var buyPrice = price.buy + 0.01
    var sellPrice = price.sell - 0.01
    if ((sellPrice - buyPrice) <= diffPrice){
        buyPrice -= 10
        sellPrice += 10
    }
    CancelPendingOrders()
    var account = _C(exchange.GetAccount)
    var amountBuy = _N((account.Balance / buyPrice-0.01), 2)
    var amountSell = _N((account.Stocks), 2)
    if (amountSell > 0.02) {
        exchange.Sell(sellPrice, amountSell)
    }
    if (amountBuy > 0.02) {
        exchange.Buy(buyPrice, amountBuy)
    }
}

function main() {
    while (true) {
        onTick()
        Sleep(Interval)
    }
}

3.6 Dual Thrust OKEX Feature

A classic breakout strategy, Check on https://www.fmz.com/strategy/103247 for configs.

You can learn how to trade features and draw charts from the source code.

learn more on https://www.quantconnect.com/tutorials/strategy-library/dual-thrust-trading-algorithm

Source code:

var ChartCfg = {
    __isStock: true,
    title: {
        text: 'Dual Thrust Up-Down Track'
    },
    yAxis: {
        plotLines: [{value: 0,
            color: 'red',
            width: 2,
            label: {
                text: 'Up Track',
                align: 'center'}
                },
            {value: 0,
            color: 'green',
            width: 2,
            label: {
                text: 'Down Track',
                align: 'center'},
            }
        ]
    },
    series: [{type: 'candlestick',
        name: 'current cycle',
        id: 'primary',
        data: []
        },
        {type: 'flags',
        onSeries: 'primary',
        data: [],
        }
    ]
};

var STATE_IDLE = 0;
var STATE_LONG = 1;
var STATE_SHORT = 2;
var State = STATE_IDLE;

var LastBarTime = 0;
var UpTrack = 0;
var BottomTrack = 0;
var chart = null;
var InitAccount = null;
var LastAccount = null;
var Counter = {
    w: 0,
    l: 0
};


function GetPosition(posType) {
    var positions = exchange.GetPosition();
    for (var i = 0; i < positions.length; i++) {
        if (positions[i].Type === posType) {
            return [positions[i].Price, positions[i].Amount];
        }
    }
    return [0, 0];
}

function CancelPendingOrders() {
    while (true) {
        var orders = exchange.GetOrders();
        for (var i = 0; i < orders.length; i++) {
            exchange.CancelOrder(orders[i].Id);
            Sleep(Interval);
        }
        if (orders.length === 0) {
            break;
        }
    }
}

function Trade(currentState, nextState) {
    var pfn = nextState === STATE_LONG ? exchange.Buy : exchange.Sell;
    if (currentState !== STATE_IDLE) {
        exchange.SetDirection(currentState === STATE_LONG ? "closebuy" : "closesell");
        while (true) {
            var amount = GetPosition(currentState === STATE_LONG ? PD_LONG : PD_SHORT)[1];
            if (amount === 0) {
                break;
            }
            // pfn(amount);
            pfn(nextState === STATE_LONG ? _C(exchange.GetTicker).Sell * 1.001 : _C(exchange.GetTicker).Buy * 0.999, amount);
            Sleep(Interval);
            CancelPendingOrders();
        }
        var account = exchange.GetAccount();

        if (account.Stocks > LastAccount.Stocks) {
            Counter.w++;
        } else {
            Counter.l++;
        }

        LogProfit(_N(account.Stocks - InitAccount.Stocks), "Profit rate:", _N((account.Stocks - InitAccount.Stocks) * 100 / InitAccount.Stocks) + '%');
        LastAccount = account;
    }
    exchange.SetDirection(nextState === STATE_LONG ? "buy" : "sell");
    while (true) {
        var pos = GetPosition(nextState === STATE_LONG ? PD_LONG : PD_SHORT);
        if (pos[1] >= AmountOP) {
            Log("Average Price", pos[0], "amount:", pos[1]);
            break;
        }
        // pfn(AmountOP-pos[1]);
        pfn(nextState === STATE_LONG ? _C(exchange.GetTicker).Sell * 1.001 : _C(exchange.GetTicker).Buy * 0.999, AmountOP-pos[1]);
        Sleep(Interval);
        CancelPendingOrders();
    }
}

function onTick(exchange) {
    var records = exchange.GetRecords();
    if (!records || records.length <= NPeriod) {
        return;
    }
    var Bar = records[records.length - 1];
    if (LastBarTime !== Bar.Time) {
        var HH = TA.Highest(records, NPeriod, 'High');
        var HC = TA.Highest(records, NPeriod, 'Close');
        var LL = TA.Lowest(records, NPeriod, 'Low');
        var LC = TA.Lowest(records, NPeriod, 'Close');

        var Range = Math.max(HH - LC, HC - LL);

        UpTrack = _N(Bar.Open + (Ks * Range));
        DownTrack = _N(Bar.Open - (Kx * Range));
        if (LastBarTime > 0) {
            var PreBar = records[records.length - 2];
            chart.add(0, [PreBar.Time, PreBar.Open, PreBar.High, PreBar.Low, PreBar.Close], -1);
        } else {
            for (var i = Math.min(records.length, NPeriod * 3); i > 1; i--) {
                var b = records[records.length - i];
                chart.add(0, [b.Time, b.Open, b.High, b.Low, b.Close]);
            }
        }
        chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close]);
        ChartCfg.yAxis.plotLines[0].value = UpTrack;
        ChartCfg.yAxis.plotLines[1].value = DownTrack;
        ChartCfg.subtitle = {
            text: 'Up Track: ' + UpTrack + '  Down Track: ' + DownTrack
        };
        chart.update(ChartCfg);
        chart.reset(PeriodShow);

        LastBarTime = Bar.Time;
    } else {
        chart.add(0, [Bar.Time, Bar.Open, Bar.High, Bar.Low, Bar.Close], -1);
    }

    LogStatus("Price:", Bar.Close, "Up:", UpTrack, "Down:", DownTrack, "Wins: ", Counter.w, "Losses:", Counter.l, "Date:", new Date());
    var msg;
    if (State === STATE_IDLE || State === STATE_SHORT) {
        if (Bar.Close >= UpTrack) {
            msg  = 'Long Price: ' + Bar.Close + ' Up Track:' + UpTrack;
            Log(msg);
            Trade(State, STATE_LONG);
            State = STATE_LONG;
            chart.add(1, {x:Bar.Time, color: 'red', shape: 'flag', title: 'Long', text: msg});
        }
    }

    if (State === STATE_IDLE || State === STATE_LONG) {
        if (Bar.Close <= DownTrack) {
            msg = 'Short Price: ' + Bar.Close + ' Down Track:' + DownTrack;
            Log(msg);
            Trade(State, STATE_SHORT);
            chart.add(1, {x:Bar.Time, color: 'green', shape: 'circlepin', title: 'Short', text: msg});
            State = STATE_SHORT;
        }
    }
}

function onexit() {
    var pos = exchange.GetPosition();
    if (pos.length > 0) {
        Log("Warning, has positions when exiting", pos);
    }
}

function main() {
    if (exchange.GetName() !== 'Futures_OKCoin') {
        throw "Only support OKEX features";
    }
    exchange.SetRate(1);
    exchange.SetContractType(["this_week", "next_week", "quarter"][ContractTypeIdx]);
    exchange.SetMarginLevel([10, 20][MarginLevelIdx]);

    if (exchange.GetPosition().length > 0) {
        throw "Can't have Positions when start.";}

    CancelPendingOrders();

    InitAccount = LastAccount = exchange.GetAccount();
    LoopInterval = Math.min(1, LoopInterval);
    Log('Exchange Name:', exchange.GetName(), InitAccount);
    LogStatus("Ready...");

    LogProfitReset();
    chart = Chart(ChartCfg);
    chart.reset();

    LoopInterval = Math.max(LoopInterval, 1);
    while (true) {
        onTick(exchange);
        Sleep(LoopInterval * 1000);
    }
}

3.7 High Frequency Marketmaker

This is a simple but powerful strategy that used to earn thousands of times in real BTC spot markets. Can’t run it on exchanges that have high trade fee.

Source code:

var floatAmountBuy = 20;
var floatAmountSell = 20;
var diffPrice = 3;
var Interval = 3000;

function CancelPendingOrders() {
    var orders = _C(exchange.GetOrders);
    for (var j = 0; j < orders.length; j++) {
        exchange.CancelOrder(orders[j].Id, orders[j]);}
}

function GetPrice(Type, depth) {
    var amountBids = 0;
    var amountAsks = 0;
    if(Type == "Buy"){
        for(var i=0;i<depth.Bids.length;i++){
            amountBids += depth.Bids[i].Amount;
            if (amountBids > floatAmountBuy){
                return depth.Bids[i].Price + 0.01;
            }
        }
    }
    if(Type == "Sell"){
        for(var j=0; j<depth.Asks.length; j++){
            amountAsks += depth.Asks[j].Amount;
            if (amountAsks > floatAmountSell){
                return depth.Asks[j].Price - 0.01;
            }
        }
    }
    return depth.Asks[0].Price
}

function onTick() {
    var depth = _C(exchange.GetDepth);
    var buyPrice = GetPrice("Buy", depth);
    var sellPrice = GetPrice("Sell", depth);
    if ((sellPrice - buyPrice) <= diffPrice){
        buyPrice -= 10;
        sellPrice += 10;
    }
    CancelPendingOrders();
    var account = _C(exchange.GetAccount);
    var amountBuy = _N((account.Balance / buyPrice-0.01), 2);
    var amountSell = _N((account.Stocks), 2);
    if (amountSell > 0.02) {
        exchange.Sell(sellPrice, amountSell);
    }
    if (amountBuy > 0.02) {
        exchange.Buy(buyPrice, amountBuy);
    }
}

function main() {
    while (true) {
        onTick();
        Sleep(Interval);
    }
}