Bermain JavaScript dengan orang tua - membuat mitra yang akan melakukan pembelian dan penjualan (4) mengajari dia pengetahuan sederhana (app linear)

Penulis:Mimpi kecil, Dibuat: 2017-03-08 11:52:02, Diperbarui: 2017-10-11 10:37:23

Bermain dengan orang tua dan orang tua JavaScript untuk menciptakan mitra yang akan melakukan pembelian dan penjualan.

Mengajarnya pengetahuan sederhana (aplikasi rata-rata)

Pada bab sebelumnya, kita telah berlatih beberapa kode yang menarik di dalam sistem kotak pasir, dan hari ini kita perlu membuat program kecil kita keluar dari kotak pasir untuk melihat dunia di luar, tentu saja kita harus mengajarkannya sesuatu terlebih dahulu!

  • Logika jual beli secara linier

    Logika jual beli ini mungkin merupakan strategi paling sederhana dan paling mendasar di dunia perdagangan terprogram, perdagangan kuantitatif. Prinsipnya sangat sederhana, yang digunakan adalah kontras rata-rata harga sejarah sehingga menentukan arah masa depan harga barang yang ditandai. Artinya: suatu benda yang ditandai seperti kontrak MA705 (kontrak metanol) siklus adalah rata-rata 10 Bar ((K kolom garis) dan siklus adalah rata-rata 8 Bar, perbedaan perbandingan. Berikutnya disebut 10 siklus ((siklus panjang) adalah garis lambat, 8 siklus ((siklus relatif pendek) adalah garis cepat, mungkin ada pembaca yang tidak mengerti, tidak masalah, kita membiarkan teman kecil menggambar dalam sistem kotak pasir ((lihatlah kode gambar di bab sebelumnya menggambar lagi gambar sederhana so easy!), Untuk kemudahan penggunaan, kode dari tumpukan gambar di edisi sebelumnya dikemas dalam satu file.

    Ini adalah alamat template gambar:https://www.fmz.com/strategy/27293

    img

    Setelah disalin, template akan muncul di dalam template referensi, gunakan langsung, dan pastikan untuk mengkliknya.

    Kode sangat sederhana:

    var PreRecordTime = 0;
    var isFirst = true;
    function MainLoop(){
        var info = exchange.SetContractType("MA705");
        if(!info){
            return;
        }
        var records = exchange.GetRecords();
        if(!records || records.length < 10){    // 因为长周期 为10 所以要计算10个Bar的均值, 必须要有10个K线才能计算出来。
            return;                             // 不满足的情况,返回,重新来。
        }
        if(isFirst){
            PreRecordTime = records[records.length - 1].Time;
            isFirst = false;
        }
      
        var fastLine = TA.MA(records, 8);       // 均线指标,计算出给定 的K线数据 8个 Bar 的均值, 按顺序压入数组(随时间序列,和K线Bar时间同步形成一条线,所以叫快线) 返回这个数组给变量fastLine
        var slowLine = TA.MA(records, 10);      // 同上 区别是10个Bar ,所以叫慢线(周期大,均值变化的慢)。
      
        var current_fastLine = fastLine[fastLine.length - 1];  // 这个数组的 倒数第一个索引 fastLine.length - 1 ,也就是表示的 快线的最后一个值 ,就是当前K线 对应的 快线均值。
        var current_slowLine = slowLine[slowLine.length - 1];  // 同上
      
        if(PreRecordTime !== records[records.length - 1].Time){ // K线更新了才确定当前最新的前一根Bar
            $.PlotLine("fastLine", fastLine[fastLine.length - 2], PreRecordTime);  // 引用了模板,可以直接使用这个模块导出函数 画线。(其实就是封装成 模块了)
            $.PlotLine("slowLine", slowLine[slowLine.length - 2], PreRecordTime);  // 同上  画指标线
            PreRecordTime = records[records.length - 1].Time;
            $.PlotLine("fastLine", current_fastLine, records[records.length - 1].Time);
            $.PlotLine("slowLine", current_slowLine, records[records.length - 1].Time); 
        }else{
            $.PlotLine("fastLine", current_fastLine, records[records.length - 1].Time);  // 当前的不停在变动。
            $.PlotLine("slowLine", current_slowLine, records[records.length - 1].Time); 
        }
        $.PlotRecords(records, "MA705");           // 画K线
    }
    
    var cfg = $.GetCfg();
    function main() {
        var status = null;
        cfg.yAxis = [{
                title: {text: 'K线'},            //标题
                style: {color: '#4572A7'},       //样式 
                opposite: false                  //生成右边Y轴
            },
           {
                title:{text: "另一个Y轴"},
                opposite: true                   //生成右边Y轴  ceshi
           }
        ];
        while(true){
            status = exchange.IO("status");      //  调用API 确定连接状态
            if(status === true){                 //  判断状态
                // LogStatus("已连接!");         //  在回测或者实际运行中显示一些实时数据、信息。
                // 由于MainLoop 中用到了LogStatus 所以这个地方的要先注释掉, 以免覆盖掉信息
                MainLoop();                      //  连接上 交易所服务器后,执行主要工作函数。
            }else{                               //  如果没有连接上 即 exchange.IO("status") 函数返回 false
                LogStatus("未连接状态!");         //  显示 未连接状态。
            }
            Sleep(1000);                         //  封装的睡眠函数,需要有轮询间隔, 以免访问过于频繁。CTP协议是每秒推送2次数据。
        }
    }
    

    Di bawah ini adalah beberapa tips untuk membuat sandbox yang bisa Anda gunakan:img

    Seperti yang kita lihat, ketika ada peningkatan lokal, garis cepat muncul dari bawah melalui garis lambat. Bagaimana bentuk ini dijelaskan dalam kode?

    // 判断指标形态
    if(fastLine.length > 3 && slowLine.length > 3 && fastLine[fastLine.length - 3] < slowLine[slowLine.length - 3] && fastLine[fastLine.length - 2] > slowLine[slowLine.length - 2]){
          $.PlotFlag(records[records.length - 2].Time, '已经交叉', 'X'); // 在图表上打个标记
    }
    

    img

    Lalu lintas cepat dari atas ke bawah melalui jalur lambat juga sama. Kami menambahkan kode ke program sesuai dengan logika ini.

  • Program Guru Belajar Berdagang secara Merata

    Di sini kita menggunakan modul lain yang ditulis dalam JavaScript, tapi saya tidak akan mengutipnya untuk pertama kalinya, dan langsung diintegrasikan ke dalam program kami. MA705 kontrak (methanol) masih digunakan sebagai tanda perdagangan.

// --------交易模块-------------
var Interval = 500;
var SlideTick = 1;
var RiskControl = false;

var __orderCount = 0
var __orderDay = 0

function CanTrade(tradeAmount) {
    if (!RiskControl) {
        return true
    }
    if (typeof(tradeAmount) == 'number' && tradeAmount > MaxTradeAmount) {
        Log("风控模块限制, 超过最大下单量", MaxTradeAmount, "#ff0000 @");
        throw "中断执行"
        return false;
    }
    var nowDay = new Date().getDate();
    if (nowDay != __orderDay) {
        __orderDay = nowDay;
        __orderCount = 0;
    }
    __orderCount++;
    if (__orderCount > MaxTrade) {
        Log("风控模块限制, 不可交易, 超过最大下单次数", MaxTrade, "#ff0000 @");
        throw "中断执行"
        return false;
    }
    return true;
}

function init() {
    if (typeof(SlideTick) === 'undefined') {
        SlideTick = 1;
    } else {
        SlideTick = parseInt(SlideTick);
    }
    Log("商品交易类库加载成功");
}

function GetPosition(e, contractType, direction, positions) {
    var allCost = 0;
    var allAmount = 0;
    var allProfit = 0;
    var allFrozen = 0;
    var posMargin = 0;
    if (typeof(positions) === 'undefined' || !positions) {
        positions = _C(e.GetPosition);
    }
    for (var i = 0; i < positions.length; i++) {
        if (positions[i].ContractType == contractType &&
            (((positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) && direction == PD_LONG) || ((positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD) && direction == PD_SHORT))
        ) {
            posMargin = positions[i].MarginLevel;
            allCost += (positions[i].Price * positions[i].Amount);
            allAmount += positions[i].Amount;
            allProfit += positions[i].Profit;
            allFrozen += positions[i].FrozenAmount;
        }
    }
    if (allAmount === 0) {
        return null;
    }
    return {
        MarginLevel: posMargin,
        FrozenAmount: allFrozen,
        Price: _N(allCost / allAmount),
        Amount: allAmount,
        Profit: allProfit,
        Type: direction,
        ContractType: contractType
    };
}


function Open(e, contractType, direction, opAmount) {
    var initPosition = GetPosition(e, contractType, direction);
    var isFirst = true;
    var initAmount = initPosition ? initPosition.Amount : 0;
    var positionNow = initPosition;
    while (true) {
        var needOpen = opAmount;
        if (isFirst) {
            isFirst = false;
        } else {
            positionNow = GetPosition(e, contractType, direction);
            if (positionNow) {
                needOpen = opAmount - (positionNow.Amount - initAmount);
            }
        }
        var insDetail = _C(e.SetContractType, contractType);
        //Log("初始持仓", initAmount, "当前持仓", positionNow, "需要加仓", needOpen);
        if (needOpen < insDetail.MinLimitOrderVolume) {
            break;
        }
        if (!CanTrade(opAmount)) {
            break;
        }
        var depth = _C(e.GetDepth);
        var amount = Math.min(insDetail.MaxLimitOrderVolume, needOpen);
        e.SetDirection(direction == PD_LONG ? "buy" : "sell");
        var orderId;
        if (direction == PD_LONG) {
            orderId = e.Buy(depth.Asks[0].Price + (insDetail.PriceTick * SlideTick), Math.min(amount, depth.Asks[0].Amount), contractType, 'Ask', depth.Asks[0]);
        } else {
            orderId = e.Sell(depth.Bids[0].Price - (insDetail.PriceTick * SlideTick), Math.min(amount, depth.Bids[0].Amount), contractType, 'Bid', depth.Bids[0]);
        }
        // CancelPendingOrders
        while (true) {
            Sleep(Interval);
            var orders = _C(e.GetOrders);
            if (orders.length === 0) {
                break;
            }
            for (var j = 0; j < orders.length; j++) {
                e.CancelOrder(orders[j].Id);
                if (j < (orders.length - 1)) {
                    Sleep(Interval);
                }
            }
        }
    }
    var ret = {
        price: 0,
        amount: 0,
        position: positionNow
    };
    if (!positionNow) {
        return ret;
    }
    if (!initPosition) {
        ret.price = positionNow.Price;
        ret.amount = positionNow.Amount;
    } else {
        ret.amount = positionNow.Amount - initPosition.Amount;
        ret.price = _N(((positionNow.Price * positionNow.Amount) - (initPosition.Price * initPosition.Amount)) / ret.amount);
    }
    return ret;
}

function Cover(e, contractType) {
    var insDetail = _C(e.SetContractType, contractType);
    while (true) {
        var n = 0;
        var opAmount = 0;
        var positions = _C(e.GetPosition);
        for (var i = 0; i < positions.length; i++) {
            if (positions[i].ContractType != contractType) {
                continue;
            }
            var amount = Math.min(insDetail.MaxLimitOrderVolume, positions[i].Amount);
            var depth;
            if (positions[i].Type == PD_LONG || positions[i].Type == PD_LONG_YD) {
                depth = _C(e.GetDepth);
                opAmount = Math.min(amount, depth.Bids[0].Amount);
                if (!CanTrade(opAmount)) {
                    return;
                }
                e.SetDirection(positions[i].Type == PD_LONG ? "closebuy_today" : "closebuy");
                
                e.Sell(depth.Bids[0].Price - (insDetail.PriceTick * SlideTick), opAmount, contractType, positions[i].Type == PD_LONG ? "平今" : "平昨", 'Bid', depth.Bids[0]);
                n++;
            } else if (positions[i].Type == PD_SHORT || positions[i].Type == PD_SHORT_YD) {
                depth = _C(e.GetDepth);
                opAmount = Math.min(amount, depth.Asks[0].Amount);
                if (!CanTrade(opAmount)) {
                    return;
                }
                e.SetDirection(positions[i].Type == PD_SHORT ? "closesell_today" : "closesell");
                e.Buy(depth.Asks[0].Price + (insDetail.PriceTick * SlideTick), opAmount, contractType, positions[i].Type == PD_SHORT ? "平今" : "平昨", 'Ask', depth.Asks[0]);
                n++;
            }
        }
        if (n === 0) {
            break;
        }
        while (true) {
            Sleep(Interval);
            var orders = _C(e.GetOrders);
            if (orders.length === 0) {
                break;
            }
            for (var j = 0; j < orders.length; j++) {
                e.CancelOrder(orders[j].Id);
                if (j < (orders.length - 1)) {
                    Sleep(Interval);
                }
            }
        }
    }
}

var PositionManager = (function() {
    function PositionManager(e) {
        if (typeof(e) === 'undefined') {
            e = exchange;
        }
        if (e.GetName() !== 'Futures_CTP') {
            throw 'Only support CTP';
        }
        this.e = e;
        this.account = null;
    }
    // Get Cache
    PositionManager.prototype.Account = function() {
        if (!this.account) {
            this.account = _C(this.e.GetAccount);
        }
        return this.account;
    };
    PositionManager.prototype.GetAccount = function(getTable) {
        this.account = _C(this.e.GetAccount);
        if (typeof(getTable) !== 'undefined' && getTable) {
            return AccountToTable(this.e.GetRawJSON())
        }
        return this.account;
    };

    PositionManager.prototype.GetPosition = function(contractType, direction, positions) {
        return GetPosition(this.e, contractType, direction, positions);
    };

    PositionManager.prototype.OpenLong = function(contractType, shares) {
        if (!this.account) {
            this.account = _C(this.e.GetAccount);
        }
        return Open(this.e, contractType, PD_LONG, shares);
    };

    PositionManager.prototype.OpenShort = function(contractType, shares) {
        if (!this.account) {
            this.account = _C(this.e.GetAccount);
        }
        return Open(this.e, contractType, PD_SHORT, shares);
    };

    PositionManager.prototype.Cover = function(contractType) {
        if (!this.account) {
            this.account = _C(this.e.GetAccount);
        }
        return Cover(this.e, contractType);
    };
    PositionManager.prototype.CoverAll = function() {
        if (!this.account) {
            this.account = _C(this.e.GetAccount);
        }
        while (true) {
            var positions = _C(this.e.GetPosition)
            if (positions.length == 0) {
                break
            }
            for (var i = 0; i < positions.length; i++) {
                // Cover Hedge Position First
                if (positions[i].ContractType.indexOf('&') != -1) {
                    Cover(this.e, positions[i].ContractType)
                    Sleep(1000)
                }
            }
            for (var i = 0; i < positions.length; i++) {
                if (positions[i].ContractType.indexOf('&') == -1) {
                    Cover(this.e, positions[i].ContractType)
                    Sleep(1000)
                }
            }
        }
    };
    PositionManager.prototype.Profit = function(contractType) {
        var accountNow = _C(this.e.GetAccount);
        return _N(accountNow.Balance - this.account.Balance);
    };

    return PositionManager;
})();

$.NewPositionManager = function(e) {
    return new PositionManager(e);
};

// Via: http://mt.sohu.com/20160429/n446860150.shtml
$.IsTrading = function(symbol) {
    var now = new Date();
    var day = now.getDay();
    var hour = now.getHours();
    var minute = now.getMinutes();

    if (day === 0 || (day === 6 && (hour > 2 || hour == 2 && minute > 30))) {
        return false;
    }
    symbol = symbol.replace('SPD ', '').replace('SP ', '');
    var p, i, shortName = "";
    for (i = 0; i < symbol.length; i++) {
        var ch = symbol.charCodeAt(i);
        if (ch >= 48 && ch <= 57) {
            break;
        }
        shortName += symbol[i].toUpperCase();
    }

    var period = [
        [9, 0, 10, 15],
        [10, 30, 11, 30],
        [13, 30, 15, 0]
    ];
    if (shortName === "IH" || shortName === "IF" || shortName === "IC") {
        period = [
            [9, 30, 11, 30],
            [13, 0, 15, 0]
        ];
    } else if (shortName === "TF" || shortName === "T") {
        period = [
            [9, 15, 11, 30],
            [13, 0, 15, 15]
        ];
    }


    if (day >= 1 && day <= 5) {
        for (i = 0; i < period.length; i++) {
            p = period[i];
            if ((hour > p[0] || (hour == p[0] && minute >= p[1])) && (hour < p[2] || (hour == p[2] && minute < p[3]))) {
                return true;
            }
        }
    }

    var nperiod = [
        [
            ['AU', 'AG'],
            [21, 0, 02, 30]
        ],
        [
            ['CU', 'AL', 'ZN', 'PB', 'SN', 'NI'],
            [21, 0, 01, 0]
        ],
        [
            ['RU', 'RB', 'HC', 'BU'],
            [21, 0, 23, 0]
        ],
        [
            ['P', 'J', 'M', 'Y', 'A', 'B', 'JM', 'I'],
            [21, 0, 23, 30]
        ],
        [
            ['SR', 'CF', 'RM', 'MA', 'TA', 'ZC', 'FG', 'IO'],
            [21, 0, 23, 30]
        ],
    ];
    for (i = 0; i < nperiod.length; i++) {
        for (var j = 0; j < nperiod[i][0].length; j++) {
            if (nperiod[i][0][j] === shortName) {
                p = nperiod[i][1];
                var condA = hour > p[0] || (hour == p[0] && minute >= p[1]);
                var condB = hour < p[2] || (hour == p[2] && minute < p[3]);
                // in one day
                if (p[2] >= p[0]) {
                    if ((day >= 1 && day <= 5) && condA && condB) {
                        return true;
                    }
                } else {
                    if (((day >= 1 && day <= 5) && condA) || ((day >= 2 && day <= 6) && condB)) {
                        return true;
                    }
                }
                return false;
            }
        }
    }
    return false;
};
// --------交易模块完结----------
var PreRecordTime = 0;
var isFirst = true;
var IDLE = 0;
var OPENLONG = 1;
var COVER = 2;
var STATE = IDLE;
var InitAccount = null;
function MainLoop(){
    var info = exchange.SetContractType("MA705");
    if(!info){
        return;
    }
    var records = exchange.GetRecords();
    if(!records || records.length < 10){    // 因为长周期 为10 所以要计算10个Bar的均值, 必须要有10个K线才能计算出来。
        return;                             // 不满足的情况,返回,重新来。
    }
    if(isFirst){
        PreRecordTime = records[records.length - 1].Time;
        InitAccount = exchange.GetAccount();
        isFirst = false;
    }
    
    var fastLine = TA.MA(records, 5);       // 均线指标,计算出给定 的K线数据 8个 Bar 的均值, 按顺序压入数组(随时间序列,和K线Bar时间同步形成一条线,所以叫快线) 返回这个数组给变量fastLine
    var slowLine = TA.MA(records, 10);      // 同上 区别是10个Bar ,所以叫慢线(周期大,均值变化的慢)。
    
    var current_fastLine = fastLine[fastLine.length - 1];  // 这个数组的 倒数第一个索引 fastLine.length - 1 ,也就是表示的 快线的最后一个值 ,就是当前K线 对应的 快线均值。
    var current_slowLine = slowLine[slowLine.length - 1];  // 同上
    
    if(PreRecordTime !== records[records.length - 1].Time){ // K线更新了才确定当前最新的前一根Bar
        $.PlotLine("fastLine", fastLine[fastLine.length - 2], PreRecordTime);  // 引用了模板,可以直接使用这个模块导出函数 画线。(其实就是封装成 模块了)
        $.PlotLine("slowLine", slowLine[slowLine.length - 2], PreRecordTime);  // 同上  画指标线
        PreRecordTime = records[records.length - 1].Time;
        $.PlotLine("fastLine", current_fastLine, records[records.length - 1].Time);
        $.PlotLine("slowLine", current_slowLine, records[records.length - 1].Time); 
    }else{
        $.PlotLine("fastLine", current_fastLine, records[records.length - 1].Time);  // 当前的不停在变动。
        $.PlotLine("slowLine", current_slowLine, records[records.length - 1].Time); 
    }
    $.PlotRecords(records, "MA705");           // 画K线
    // 判断指标形态
    if(STATE === IDLE && fastLine.length > 3 && slowLine.length > 3 && fastLine[fastLine.length - 3] < slowLine[slowLine.length - 3] && fastLine[fastLine.length - 2] > slowLine[slowLine.length - 2]){
        P.OpenLong("MA705", 1);
        STATE = OPENLONG;
        $.PlotFlag(new Date().getTime(), '快线上传慢线', 'OPENLONG');
    }
    if(STATE === OPENLONG && fastLine[fastLine.length - 3] > slowLine[slowLine.length - 3] && fastLine[fastLine.length - 2] < slowLine[slowLine.length - 2]){
        P.Cover("MA705");
        STATE = COVER;   
        $.PlotFlag(new Date().getTime(), '快线下传慢线', 'COVER');
    }
    if(STATE === COVER){
        var nowAccount = exchange.GetAccount();
        LogProfit(nowAccount.Balance - InitAccount.Balance, nowAccount);
        STATE = IDLE;
    }
}

var cfg = $.GetCfg();
var P = null;
function main() {
    var status = null;
    P = $.NewPositionManager(exchange);      // 构造一个 用于控制交易细节的对象。
    cfg.yAxis = [{
            title: {text: 'K线'},            //标题
            style: {color: '#4572A7'},       //样式 
            opposite: false                  //生成右边Y轴
        },
       {
            title:{text: "另一个Y轴"},
            opposite: true                   //生成右边Y轴  ceshi
       }
    ];
    while(true){
        status = exchange.IO("status");      //  调用API 确定连接状态
        if(status === true){                 //  判断状态
            // LogStatus("已连接!");         //  在回测或者实际运行中显示一些实时数据、信息。
            // 由于MainLoop 中用到了LogStatus 所以这个地方的要先注释掉, 以免覆盖掉信息
            MainLoop();                      //  连接上 交易所服务器后,执行主要工作函数。
        }else{                               //  如果没有连接上 即 exchange.IO("status") 函数返回 false
            LogStatus("未连接状态!");         //  显示 未连接状态。
        }
        Sleep(1000);                         //  封装的睡眠函数,需要有轮询间隔, 以免访问过于频繁。CTP协议是每秒推送2次数据。
    }
}

Sandbox ini memiliki hasil yang sangat baik.

img img img

Pada saat ini, pasar yang bergoyang-goyang telah mengalami penurunan yang besar, dan logik perdagangan ini sangat tidak sempurna, keuntungan positif dalam tren naik, tidak berarti tidak ada masalah ((pasar yang bergoyang mungkin terguncang =_=)).
  • "Memulai dari kotak pasir dan melihat dunia di luar. Bermain dengan simulator futures simulasi akun simnow yang ditawarkan oleh teknologi Simnow.

    Untuk informasi lebih lanjut tentang aplikasi simnow Commodity Futures Simulator Account, Anda dapat melihat posting ini:https://www.fmz.com/bbs-topic/325Perdagangan analog dapat diprogram langsung dengan menggunakan protokol CTP.

    Program ini berjalan untuk sementara waktu, strategi itu sendiri bersifat demonstratif, hanya untuk referensi, jika perlu disempurnakan juga dapat ditambahkan kontrol posisi, stop stop stop stop, pemberitahuan posisi awal, dll.

    img

    Akun palsu, bisa di tes ini. (bukan uang sungguhan!

    Lihatlah program lain saya yang berjalan di piringan simulasi, yang menunjukkan sedikit kompleksitas ini:

    img

    Saya suka bermain JS, belajar tentang JS, ambil, source code:https://www.fmz.com/strategy/17289

    img

    img

Sebelum menulis ini, selamat datang pembaca untuk meninggalkan saya komentar! memberikan saran dan saran, jika Anda merasa menyenangkan dapat dibagikan kepada lebih banyak teman yang menyukai program yang suka perdagangan

https://www.fmz.com/bbs-topic/727

Pemrogram LittleDream


Lebih banyak