-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Trial implementation of a CrossInstrument class.
- Loading branch information
reiss
authored and
reiss
committed
Nov 8, 2017
1 parent
988fe9d
commit c43b8f3
Showing
3 changed files
with
196 additions
and
0 deletions.
There are no files selected for viewing
96 changes: 96 additions & 0 deletions
96
src/main/java/com/jforex/programming/instrument/CrossInstrument.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package com.jforex.programming.instrument; | ||
|
||
import static java.util.stream.Collectors.toSet; | ||
|
||
import java.math.BigDecimal; | ||
import java.math.RoundingMode; | ||
|
||
import com.dukascopy.api.ICurrency; | ||
import com.dukascopy.api.Instrument; | ||
import com.google.common.collect.Sets; | ||
import com.jforex.programming.currency.CurrencyFactory; | ||
import com.jforex.programming.currency.CurrencyUtil; | ||
|
||
import io.reactivex.Maybe; | ||
|
||
public class CrossInstrument { | ||
|
||
private final Instrument firstInstrument; | ||
private final Instrument secondInstrument; | ||
private final Instrument instrument; | ||
private final ICurrency crossCurrency; | ||
private final boolean isEmpty; | ||
private final boolean shouldDivide; | ||
private final int pipScale; | ||
|
||
public CrossInstrument(final Instrument firstInstrument, | ||
final Instrument secondInstrument) { | ||
this.firstInstrument = firstInstrument; | ||
this.secondInstrument = secondInstrument; | ||
|
||
final Maybe<Instrument> maybeCross = InstrumentFactory.maybeCross(firstInstrument, secondInstrument); | ||
|
||
instrument = maybeCross.blockingGet(); | ||
isEmpty = maybeCross | ||
.isEmpty() | ||
.blockingGet(); | ||
crossCurrency = calcCrossCurrency(); | ||
shouldDivide = shouldDivide(); | ||
pipScale = instrument.getPipScale() + 1; | ||
} | ||
|
||
public boolean isValid() { | ||
return !isEmpty; | ||
} | ||
|
||
public Instrument get() { | ||
return instrument; | ||
} | ||
|
||
public ICurrency crossCurrency() { | ||
return crossCurrency; | ||
} | ||
|
||
public FxRate rate(final FxRate rateA, | ||
final FxRate rateB) { | ||
final BigDecimal bdcFirst = rateA.instrument().equals(firstInstrument) | ||
? BigDecimal.valueOf(rateA.value()) | ||
: BigDecimal.valueOf(rateB.value()); | ||
final BigDecimal bdcSecond = rateB.instrument().equals(secondInstrument) | ||
? BigDecimal.valueOf(rateB.value()) | ||
: BigDecimal.valueOf(rateA.value()); | ||
|
||
final double crossValue = shouldDivide | ||
? bdcFirst.divide(bdcSecond, | ||
pipScale, | ||
RoundingMode.HALF_UP) | ||
.doubleValue() | ||
: bdcFirst | ||
.multiply(bdcSecond) | ||
.setScale(pipScale, RoundingMode.HALF_UP) | ||
.doubleValue(); | ||
|
||
return new FxRate(crossValue, instrument); | ||
} | ||
|
||
private ICurrency calcCrossCurrency() { | ||
return CurrencyFactory | ||
.fromInstruments(firstInstrument, secondInstrument) | ||
.stream() | ||
.filter(currency -> CurrencyUtil.isInAllInstruments(currency, | ||
Sets.newHashSet(firstInstrument, secondInstrument))) | ||
.collect(toSet()) | ||
.iterator() | ||
.next(); | ||
} | ||
|
||
private boolean shouldDivide() { | ||
final ICurrency baseFirstCurrency = firstInstrument.getPrimaryJFCurrency(); | ||
final ICurrency baseSecondCurrency = secondInstrument.getPrimaryJFCurrency(); | ||
final ICurrency quoteFirstCurrency = firstInstrument.getSecondaryJFCurrency(); | ||
final ICurrency quoteSecondCurrency = secondInstrument.getSecondaryJFCurrency(); | ||
|
||
return baseFirstCurrency.equals(crossCurrency) && baseSecondCurrency.equals(crossCurrency) | ||
|| quoteFirstCurrency.equals(crossCurrency) && quoteSecondCurrency.equals(crossCurrency); | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/java/com/jforex/programming/instrument/FxRate.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.jforex.programming.instrument; | ||
|
||
import com.dukascopy.api.Instrument; | ||
|
||
public class FxRate { | ||
|
||
private final double value; | ||
private final Instrument instrument; | ||
|
||
public FxRate(final double value, | ||
final Instrument instrument) { | ||
this.value = value; | ||
this.instrument = instrument; | ||
} | ||
|
||
public double value() { | ||
return value; | ||
} | ||
|
||
public Instrument instrument() { | ||
return instrument; | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
src/test/java/com/jforex/programming/instrument/test/CrossInstrumentTest.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.jforex.programming.instrument.test; | ||
|
||
import static org.hamcrest.Matchers.equalTo; | ||
import static org.junit.Assert.assertThat; | ||
import static org.junit.Assert.assertTrue; | ||
|
||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
import com.jforex.programming.instrument.CrossInstrument; | ||
import com.jforex.programming.instrument.FxRate; | ||
import com.jforex.programming.test.common.CurrencyUtilForTest; | ||
|
||
public class CrossInstrumentTest extends CurrencyUtilForTest { | ||
|
||
private CrossInstrument crossInstrumentA; | ||
private CrossInstrument crossInstrumentB; | ||
private CrossInstrument crossInstrumentC; | ||
private CrossInstrument crossInstrumentD; | ||
|
||
@Before | ||
public void setUp() { | ||
crossInstrumentA = new CrossInstrument(instrumentEURUSD, instrumentGBPUSD); | ||
crossInstrumentB = new CrossInstrument(instrumentEURGBP, instrumentGBPUSD); | ||
crossInstrumentC = new CrossInstrument(instrumentEURJPY, instrumentGBPJPY); | ||
crossInstrumentD = new CrossInstrument(instrumentEURGBP, instrumentGBPJPY); | ||
} | ||
|
||
@Test | ||
public void instanceIsValid() { | ||
assertTrue(crossInstrumentA.isValid()); | ||
assertTrue(crossInstrumentB.isValid()); | ||
assertTrue(crossInstrumentC.isValid()); | ||
assertTrue(crossInstrumentD.isValid()); | ||
} | ||
|
||
@Test | ||
public void instrumentIsCorrect() { | ||
assertThat(crossInstrumentA.get(), equalTo(instrumentEURGBP)); | ||
assertThat(crossInstrumentB.get(), equalTo(instrumentEURUSD)); | ||
assertThat(crossInstrumentC.get(), equalTo(instrumentEURGBP)); | ||
assertThat(crossInstrumentD.get(), equalTo(instrumentEURJPY)); | ||
} | ||
|
||
@Test | ||
public void crossCurrencyIsCorrect() { | ||
assertThat(crossInstrumentA.crossCurrency(), equalTo(currencyUSD)); | ||
assertThat(crossInstrumentB.crossCurrency(), equalTo(currencyGBP)); | ||
assertThat(crossInstrumentC.crossCurrency(), equalTo(currencyJPY)); | ||
assertThat(crossInstrumentD.crossCurrency(), equalTo(currencyGBP)); | ||
} | ||
|
||
@Test | ||
public void crossRateIsCorrect() { | ||
FxRate rateA = new FxRate(1.15863, instrumentEURUSD); | ||
FxRate rateB = new FxRate(1.31044, instrumentGBPUSD); | ||
assertThat(crossInstrumentA.rate(rateA, rateB).value(), | ||
equalTo(0.88415)); | ||
assertThat(crossInstrumentA.rate(rateA, rateB).instrument(), | ||
equalTo(instrumentEURGBP)); | ||
|
||
rateA = new FxRate(0.88415, instrumentEURGBP); | ||
rateB = new FxRate(1.31044, instrumentGBPUSD); | ||
assertThat(crossInstrumentB.rate(rateA, rateB).value(), | ||
equalTo(1.15863)); | ||
|
||
rateA = new FxRate(131.452, instrumentEURJPY); | ||
rateB = new FxRate(148.653, instrumentGBPJPY); | ||
assertThat(crossInstrumentC.rate(rateA, rateB).value(), | ||
equalTo(0.88429)); | ||
|
||
rateA = new FxRate(0.88429, instrumentEURGBP); | ||
rateB = new FxRate(148.653, instrumentGBPJPY); | ||
assertThat(crossInstrumentD.rate(rateA, rateB).value(), | ||
equalTo(131.452)); | ||
} | ||
} |