Last active
April 8, 2018 21:17
-
-
Save Synesso/1d25c953a7090e0ae1bb67a2acdded63 to your computer and use it in GitHub Desktop.
Analysis of gap trades using MT4 data extracts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.time._ | |
import scala.io._ | |
import scala.util._ | |
case class Candle(dateTime: LocalDateTime, open: Double, high: Double, low: Double, close: Double) | |
val significant = 0.003 | |
val formatter = java.time.format.DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm") | |
def parseCandle(s: String): Try[Candle] = Try { | |
val Array(day, hour, open, high, low, close, _) = s.split(",") | |
Candle( | |
LocalDateTime.parse(s"$day $hour", formatter), | |
open.toDouble, | |
high.toDouble, | |
low.toDouble, | |
close.toDouble | |
) | |
} | |
val candles = Source.fromFile("GBPJPY4HR.csv").getLines.flatMap(parseCandle(_).toOption).toSeq | |
def epochSecond(dt: LocalDateTime) = dt.toEpochSecond(ZoneOffset.UTC) | |
def closesGap(last: Candle, first: Candle, current: Candle): Boolean = { | |
(last.close > first.open && current.high >= last.close) || | |
(last.close <= first.open && current.low <= last.close) | |
} | |
def closedBetween(l: Candle, r: Candle): Boolean = r.dateTime.compareTo(l.dateTime) > 1 | |
def hoursSince(first: Candle, current: Candle): Long = (epochSecond(current.dateTime) - epochSecond(first.dateTime)) / 3600 | |
val z = Seq.empty[(Candle, Candle, Option[Candle])] | |
val gapCloses = candles.sliding(2).foldLeft(z) { | |
// l & r gap: add (l, r, None) | |
case (xs, Seq(l, r)) if closedBetween(l, r) => (l, r, None) +: xs | |
// acc is empty: do nothing | |
case (Nil, _) => Nil | |
// head is empty; r is too long after first: do nothing | |
case ((last, first, None) +: t, Seq(_, r)) if hoursSince(first, r) >= 24 => (last, first, None) +: t | |
// head is empty; r closes gap: modify to (last, first, Some(r)) | |
case ((last, first, None) +: t, Seq(_, r)) if closesGap(last, first, r) => (last, first, Some(r)) +: t | |
// otherwise: do nothing | |
case (xs, _) => xs | |
}.reverse | |
def gap(last: Candle, first: Candle): Double = { | |
BigDecimal(math.abs(last.close - first.open)).setScale(6, BigDecimal.RoundingMode.HALF_UP).toDouble | |
} | |
def direction(last: Candle, first: Candle): String = { | |
val diff = gap(last, first) | |
if (last.close < first.open) f"up $diff%02f" | |
else f"down $diff%02f" | |
} | |
gapCloses.foreach { | |
case (last, first, None) => | |
println(s"${first.dateTime} gapped ${direction(last, first)} and did not close the gap within 24 hours") | |
case (last, first, Some(closed)) => | |
println(s"${first.dateTime} gapped ${direction(last, first)} and closed the gap within ${hoursSince(first, closed)} hours") | |
} | |
// percentage of more than 5pts gap | |
val (bigGaps, smallGaps) = gapCloses.partition{ case (last, first, _) => math.abs(gap(last, first)) >= significant } | |
val (closed, notClosed) = bigGaps.partition(_._3.nonEmpty) | |
val all = gapCloses.size | |
val smalls = smallGaps.size | |
val bigs = bigGaps.size | |
val closedBigs = closed.size | |
val unclosedBigs = notClosed.size | |
val avgAllGaps = { | |
val gaps = gapCloses.map{ case (last, first, _) => math.abs(gap(last, first)) } | |
gaps.sum * 1.0 / gaps.length | |
} | |
val avgBigGaps = { | |
val gaps = bigGaps.map{ case (last, first, _) => math.abs(gap(last, first)) } | |
gaps.sum * 1.0 / gaps.length | |
} | |
println(s"$smalls gaps < $significant ${smalls * 1.0 / all * 100.0}%") | |
println(s"$bigs gaps >= $significant ${bigs * 1.0 / all * 100.0}%") | |
println(s"$closedBigs of the big gaps are closed ${closedBigs * 1.0 / all * 100.0}% of all, ${closedBigs * 1.0 / bigs * 100.0}% of bigs") | |
println(s"$unclosedBigs of the big gaps are not closed ${unclosedBigs * 1.0 / all * 100.0}% of all, ${unclosedBigs * 1.0 / bigs * 100.0}% of bigs") | |
println(f"Average gap size of all gaps = $avgAllGaps%02f") | |
println(f"Average gap size of big gaps = $avgBigGaps%02f") |
AUS2004HR
23 gaps < 5.0 35.38461538461539%
42 gaps >= 5.0 64.61538461538461%
26 of the big gaps are closed 40.0%
16 of the big gaps are not closed 24.615384615384617%
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
AUDUSD4HR