主に裁量取引で利用している、jForexについて。今回は、サンプルコード。
自分のトレードの精度がイマイチ悪く、というか自分を律し切れていないという何とも情けない状況が続き、また本格的に自動売買プログラムを作り始めています。
今の取引手法を機械的に実施できるようにすることが目的です。
過去の経験から、処理パフォーマンス(主にTick処理ありのバックテストに耐えうる構成)や再利用性などなど、いろいろ考慮しながら作っています。
jForexでは、Tick単位でのバックテストが標準で可能ですが、PCに非常に負荷がかかりますし、時間も相当必要とします。
と脱線しましたが、今回はチャートに円を書くストラテジ、、、これをストラテジというのか。
とりあえず、夢に向かっての何度目かの第1歩です。
最近ブログで、こんなチャートを掲載することがありますが、これらのインディケータを一通り計算し、結果を蓄積するコードも書かれています。
押し込んだときにエントリし、
利益を伸ばすように我慢するような、システムが最終目標です。
↑ ※このようなコードは書かれていません
サンプルコードの実行結果がこれです。
気持ちいいぐらい、円しか書かないストラテジです。
ピンクの線は、jForex本体のEMA(20)計算結果でして、データ蓄積とかうまくいっているのか確認する為に、テスト後に描写させています。
円の中心(ストラテジの処理結果)と、jForexの計算結果が同じですね。
:::サンプルコード::: 円を描く意外に、ちまちまいろいろ処理が書かれています。が、ポジションをオープンなどの自動取引は一切しません。
package jforex; import java.awt.*; import java.math.*; import java.text.*; import java.util.*; import java.util.concurrent.*; import com.dukascopy.api.*; import com.dukascopy.api.drawings.*; import com.dukascopy.api.IEngine.OrderCommand; import com.dukascopy.api.IIndicators.AppliedPrice; import com.dukascopy.api.IIndicators.MaType; /* @author: Life with FX */ public class GarnetGlow implements IStrategy { private final String sID = "GGL"; private final String rID = "000"; private IEngine engine; private IConsole console; private IHistory history; private IContext context; private IIndicators indicators; private IUserInterface userInterface; private IChart chart = null; private IChartObjectFactory factory = null; private LfxMarketInfo mkInfo; private LfxChartUtil chartUtil; public void onStart(IContext context) throws JFException { this.engine = context.getEngine(); this.console = context.getConsole(); this.history = context.getHistory(); this.context = context; this.indicators = context.getIndicators(); this.userInterface = context.getUserInterface(); this.mkInfo = new LfxMarketInfo(context, Instrument.EURUSD); this.mkInfo.init(); this.chartUtil = new LfxChartUtil(context, Instrument.EURUSD); } public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException { // skip day off if (askBar.getVolume() < 0.5) { return; } if (instrument != Instrument.EURUSD) { return; } this.mkInfo.updateMarketInfo(instrument, period, askBar, bidBar); if (period == Period.FIVE_MINS) { Deque que = this.mkInfo.getQ5mEma(); this.chartUtil.drawEllipseOnChart(instrument, period, bidBar, Color.CYAN, que.getLast()); } } /******************************************************************************** * NOT USE ********************************************************************************/ public void onMessage(IMessage message) throws JFException { } public void onAccount(IAccount account) throws JFException { } public void onStop() throws JFException { } public void onTick(Instrument instrument, ITick tick) throws JFException { } } class LfxMarketInfo { public static final int ICHIMOKU_TENKAN = 0; public static final int ICHIMOKU_KIJYUN = 1; public static final int ICHIMOKU_CHIKOU = 2; public static final int ICHIMOKU_SENKOU_A = 3; public static final int ICHIMOKU_SENKOU_B = 4; public static final int ICHIMOKU_CLOUD_A = 5; public static final int ICHIMOKU_CLOUD_B = 6; public static final int MAMA_MAMA = 0; public static final int MAMA_FAMA = 1; public static final int FRACTALLINES_HIGH = 0; public static final int FRACTALLINES_LOW = 1; public static final int AWESOME_ZERO = 0; public static final int AWESOME_POSITIVE = 1; public static final int AWESOME_NEGATIVE = 2; public static final int STOCHF_FAST_K = 0; public static final int STOCHF_FAST_D = 1; public static final int KELTNER_UP = 0; public static final int KELTNER_MID = 1; public static final int KELTNER_LOW = 2; private IEngine engine; private IConsole console; private IHistory history; private IContext context; private IIndicators indicators; private Instrument managingInstrument; private boolean isInitialized; private final int QUEUE_SIZE = 60; private LinkedBlockingDeque q5mEma; private LinkedBlockingDeque q5mIchimokuSenkouB; private LinkedBlockingDeque q5mMamaFama; private LinkedBlockingDeque q5mFractalLineHigh; private LinkedBlockingDeque q5mFractalLineLow; private LinkedBlockingDeque q5mRci; private LinkedBlockingDeque q5mAwesome; private LinkedBlockingDeque q5mStochFK; private LinkedBlockingDeque q5mStochFD; private LinkedBlockingDeque q5mAtrS; private LinkedBlockingDeque q5mAtrL; private LinkedBlockingDeque q5mWaddahAttar; private LinkedBlockingDeque q1hKeltnerUp; private LinkedBlockingDeque q1hKeltnerMid; private LinkedBlockingDeque q1hKeltnerLow; private LinkedBlockingDeque q1hMaPrice; public LfxMarketInfo(IContext context, Instrument instrument) { this.engine = context.getEngine(); this.console = context.getConsole(); this.history = context.getHistory(); this.context = context; this.indicators = context.getIndicators(); this.managingInstrument = instrument; this.q5mEma = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mIchimokuSenkouB = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mMamaFama = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mFractalLineHigh = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mFractalLineLow = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mRci = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mAwesome = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mStochFK = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mStochFD = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mAtrS = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mAtrL = new LinkedBlockingDeque(QUEUE_SIZE); this.q5mWaddahAttar = new LinkedBlockingDeque(QUEUE_SIZE); this.q1hKeltnerUp = new LinkedBlockingDeque(QUEUE_SIZE); this.q1hKeltnerMid = new LinkedBlockingDeque(QUEUE_SIZE); this.q1hKeltnerLow = new LinkedBlockingDeque(QUEUE_SIZE); this.q1hMaPrice = new LinkedBlockingDeque(QUEUE_SIZE); } public boolean isInitialized() { return this.isInitialized; } public void init() throws JFException { int i; IBar firstBidbar5M = this.history.getBar(this.managingInstrument, Period.FIVE_MINS, OfferSide.BID, 1); IBar firstAskbar5M = this.history.getBar(this.managingInstrument, Period.FIVE_MINS, OfferSide.ASK, 1); IBar firstBidbar15M = this.history.getBar(this.managingInstrument, Period.FIFTEEN_MINS, OfferSide.BID, 1); IBar firstAskbar15M = this.history.getBar(this.managingInstrument, Period.FIFTEEN_MINS, OfferSide.ASK, 1); IBar firstBidbar1H = this.history.getBar(this.managingInstrument, Period.ONE_HOUR, OfferSide.BID, 1); IBar firstAskbar1H = this.history.getBar(this.managingInstrument, Period.ONE_HOUR, OfferSide.ASK, 1); for (i = QUEUE_SIZE; i > 0; i--) { updateMarketInfo(this.managingInstrument, Period.FIVE_MINS, firstAskbar5M, firstBidbar5M, i); updateMarketInfo(this.managingInstrument, Period.FIFTEEN_MINS, firstAskbar15M, firstBidbar15M, i); updateMarketInfo(this.managingInstrument, Period.ONE_HOUR, firstAskbar1H, firstBidbar1H, i); } this.isInitialized = true; } private boolean updateMarketInfo(Instrument instrument, Period period, IBar askBar, IBar bidBar, int shift) throws JFException { if (period == Period.FIVE_MINS) { updateMarketInfo5Mins(instrument, period, askBar, bidBar, shift); } else if (period == Period.FIFTEEN_MINS) { updateMarketInfo15Mins(instrument, period, askBar, bidBar, shift); } else if (period == Period.ONE_HOUR) { updateMarketInfo1Hour(instrument, period, askBar, bidBar, shift); } else { return false; } return true; } public boolean updateMarketInfo(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException { if (instrument != this.managingInstrument) { this.console.getOut().println("wrong instrument!!"); return false; } if (period == Period.FIVE_MINS) { updateMarketInfo5Mins(instrument, period, askBar, bidBar); } else if (period == Period.FIFTEEN_MINS) { updateMarketInfo15Mins(instrument, period, askBar, bidBar); } else if (period == Period.ONE_HOUR) { updateMarketInfo1Hour(instrument, period, askBar, bidBar); } else { return false; } return true; } private boolean updateMarketInfo5Mins(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException { return updateMarketInfo5Mins(instrument, period, askBar, bidBar, 1); } private boolean updateMarketInfo5Mins(Instrument instrument, Period period, IBar askBar, IBar bidBar, int shift) throws JFException { // INDICATOR-01 double ema = this.indicators.ema(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, 20, shift); // INDICATOR-02 double[] ichimoku = this.indicators.ichimoku(instrument, period, OfferSide.BID, 9, 26, 52, shift); // INDICATOR-03 double[] mama = this.indicators.mama(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, 0.3, 0.05, shift); // INDICATOR-04 double[] fractal = this.indicators.fractalLines(instrument, period, OfferSide.BID, 12, shift); // INDICATOR-05 double rci = this.indicators.rci(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, 36, shift); // INDICATOR-06 double[] awesome = this.indicators.awesome(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, 4, IIndicators.MaType.T3, 21, IIndicators.MaType.T3, shift); // INDICATOR-07 double[] stochF = this.indicators.stochF(instrument, period, OfferSide.BID, 12, 4, IIndicators.MaType.EMA, shift); // INDICATOR-08 double atrS = this.indicators.atr(instrument, period, OfferSide.BID, 12, shift); // INDICATOR-09 double atrL = this.indicators.atr(instrument, period, OfferSide.BID, 24, shift); // INDICATOR-10 double waddahAttar = this.indicators.waddahAttar(instrument, period, OfferSide.BID, shift); // if (!this.q5mEma.offer(ema)) { this.q5mEma.poll(); this.q5mEma.offer(ema); } if (!this.q5mIchimokuSenkouB.offer(ichimoku[ICHIMOKU_SENKOU_B])) { this.q5mIchimokuSenkouB.poll(); this.q5mIchimokuSenkouB.offer(ichimoku[ICHIMOKU_SENKOU_B]); } if (!this.q5mMamaFama.offer(mama[MAMA_FAMA])) { this.q5mMamaFama.poll(); this.q5mMamaFama.offer(mama[MAMA_FAMA]); } if (!this.q5mFractalLineHigh.offer(fractal[FRACTALLINES_HIGH])) { this.q5mFractalLineHigh.poll(); this.q5mFractalLineHigh.offer(fractal[FRACTALLINES_HIGH]); } if (!this.q5mFractalLineLow.offer(fractal[FRACTALLINES_LOW])) { this.q5mFractalLineLow.poll(); this.q5mFractalLineLow.offer(fractal[FRACTALLINES_LOW]); } if (!this.q5mRci.offer(rci)) { this.q5mRci.poll(); this.q5mRci.offer(rci); } double awesomeVal; if (!Double.isNaN(awesome[AWESOME_POSITIVE])) { awesomeVal = awesome[AWESOME_POSITIVE]; } else { awesomeVal = awesome[AWESOME_NEGATIVE]; } if (!this.q5mAwesome.offer(awesomeVal)) { this.q5mAwesome.poll(); this.q5mAwesome.offer(awesomeVal); } if (!this.q5mStochFK.offer(stochF[STOCHF_FAST_K])) { this.q5mStochFK.poll(); this.q5mStochFK.offer(stochF[STOCHF_FAST_K]); } if (!this.q5mStochFD.offer(stochF[STOCHF_FAST_D])) { this.q5mStochFD.poll(); this.q5mStochFD.offer(stochF[STOCHF_FAST_D]); } if (!this.q5mAtrS.offer(atrS)) { this.q5mAtrS.poll(); this.q5mAtrS.offer(atrS); } if (!this.q5mAtrL.offer(atrL)) { this.q5mAtrL.poll(); this.q5mAtrL.offer(atrL); } if (!this.q5mWaddahAttar.offer(waddahAttar)) { this.q5mWaddahAttar.poll(); this.q5mWaddahAttar.offer(waddahAttar); } return true; } private boolean updateMarketInfo15Mins(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException { return updateMarketInfo15Mins(instrument, period, askBar, bidBar, 1); } private boolean updateMarketInfo15Mins(Instrument instrument, Period period, IBar askBar, IBar bidBar, int shift) throws JFException { return true; } private boolean updateMarketInfo1Hour(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException { return updateMarketInfo1Hour(instrument, period, askBar, bidBar, 1); } private boolean updateMarketInfo1Hour(Instrument instrument, Period period, IBar askBar, IBar bidBar, int shift) throws JFException { long targetBarStartTime = this.history.getTimeForNBarsBack(Period.ONE_HOUR, bidBar.getTime(), shift); java.util.List bars = this.history.getBars(instrument, period, OfferSide.BID, Filter.ALL_FLATS, 24, targetBarStartTime, 0); long pastNBarStartTime = bars.get(0).getTime(); double keltner[][] = this.indicators.keltner(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, 12, Filter.ALL_FLATS, pastNBarStartTime, targetBarStartTime); double[] keltnerUp = keltner[KELTNER_UP]; double[] keltnerMid = keltner[KELTNER_MID]; double[] keltnerLow = keltner[KELTNER_LOW]; double[] ima = this.indicators.ma(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, 4, IIndicators.MaType.TRIMA, Filter.ALL_FLATS, pastNBarStartTime, targetBarStartTime); // if (!q1hKeltnerUp.offer(keltnerUp[keltnerUp.length - 1])) { q1hKeltnerUp.poll(); q1hKeltnerUp.offer(keltnerUp[keltnerUp.length - 1]); } if (!q1hKeltnerMid.offer(keltnerMid[keltnerMid.length - 1])) { q1hKeltnerMid.poll(); q1hKeltnerMid.offer(keltnerMid[keltnerMid.length - 1]); } if (!q1hKeltnerLow.offer(keltnerLow[keltnerLow.length - 1])) { q1hKeltnerLow.poll(); q1hKeltnerLow.offer(keltnerLow[keltnerLow.length - 1]); } if (!q1hMaPrice.offer(ima[ima.length - 1])) { q1hMaPrice.poll(); q1hMaPrice.offer(ima[ima.length - 1]); } return true; } public Deque getQ5mEma() { return this.q5mEma; } } class LfxChartUtil { private IEngine engine; private IConsole console; private IHistory history; private IContext context; private IIndicators indicators; private IChart chart; private Instrument managingInstrument; private boolean isDrawable; public LfxChartUtil(IContext context, Instrument instrument) { this.engine = context.getEngine(); this.console = context.getConsole(); this.history = context.getHistory(); this.context = context; this.indicators = context.getIndicators(); this.managingInstrument = instrument; this.chart = this.context.getChart(instrument); if (chart == null) { this.isDrawable = false; } else { this.isDrawable = true; } } public void setUndrawable() { this.isDrawable = false; } private boolean isManagingInstrument(Instrument instrument) { if (instrument == this.managingInstrument) { return true; } else { return false; } } public void drawArrowUpOnChart(Instrument instrument, Period period, IBar bar, Color color) throws JFException { if (this.isDrawable) { IChartObjectFactory factory = this.chart.getChartObjectFactory(); ISignalUpChartObject signal = factory.createSignalUp("AU" + bar.getTime(), bar.getTime(), bar.getLow()); signal.setColor(color); this.chart.addToMainChart(signal); } } public void drawArrowDownOnChart(Instrument instrument, Period period, IBar bar, Color color) throws JFException { if (this.isDrawable) { IChartObjectFactory factory = this.chart.getChartObjectFactory(); ISignalDownChartObject signal = factory.createSignalDown("AD" + bar.getTime(), bar.getTime(), bar.getHigh()); signal.setColor(color); chart.addToMainChart(signal); signal.setColor(color); this.chart.addToMainChart(signal); } } public void drawEllipseOnChart(Instrument instrument, Period period, IBar bar, Color color) throws JFException { if (this.isDrawable && isManagingInstrument(instrument)) { IChartObjectFactory factory = this.chart.getChartObjectFactory(); IEllipseChartObject ellipse = factory.createEllipse("EM" + bar.getTime(), this.history.getPreviousBarStart(period, bar.getTime()), bar.getClose() + (1.5 * instrument.getPipValue()), this.history.getNextBarStart(period, bar.getTime()), bar.getClose() - (1.5 * instrument.getPipValue())); ellipse.setColor(color); chart.addToMainChart(ellipse); } } public void drawEllipseOnChart(Instrument instrument, Period period, IBar bar, Color color, double price) throws JFException { if (this.isDrawable && isManagingInstrument(instrument)) { IChartObjectFactory factory = this.chart.getChartObjectFactory(); IEllipseChartObject ellipse = factory.createEllipse("EM" + bar.getTime(), this.history.getPreviousBarStart(period, bar.getTime()), price + (1.5 * instrument.getPipValue()), this.history.getNextBarStart(period, bar.getTime()), price - (1.5 * instrument.getPipValue())); ellipse.setColor(color); chart.addToMainChart(ellipse); } } }