Skip to content

Commit

Permalink
fixed findings 2
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaron committed Aug 5, 2024
1 parent 5b3711b commit 55f61f0
Show file tree
Hide file tree
Showing 16 changed files with 311 additions and 119 deletions.
11 changes: 10 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
~ limitations under the License.
-->

<!--suppress PackageUpdate -->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
Expand Down Expand Up @@ -69,7 +70,7 @@
<kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.jvmTarget>17</kotlin.compiler.jvmTarget>
<kotlin.compiler.incremental>false</kotlin.compiler.incremental>
<kotlin.version>1.9.24</kotlin.version>
<kotlin.version>1.9.25</kotlin.version>
<kotlin.compiler.languageVersion>1.9</kotlin.compiler.languageVersion>
<kotlin.compiler.apiVersion>1.9</kotlin.compiler.apiVersion>
<slf4j.version>2.0.13</slf4j.version>
Expand Down Expand Up @@ -467,6 +468,7 @@
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>

</dependencies>

<!-- Dependencies used by some modules -->
Expand All @@ -484,6 +486,13 @@
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<artifactId>roboquant</artifactId>
<groupId>org.roboquant</groupId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
6 changes: 6 additions & 0 deletions roboquant-charts/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<artifactId>roboquant</artifactId>
<groupId>org.roboquant</groupId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,6 @@ class IBKRBroker(
*/
private inner class Wrapper(logger: Logging.Logger) : BaseWrapper(logger) {

val accountTags = mutableMapOf(
AccountSummaryTag.TotalCashValue to Amount(Currency.USD, 0),
AccountSummaryTag.BuyingPower to Amount(Currency.USD, 0),
)

/**
* Convert an IBOrder to a roboquant Instruction.
* This is only used during initial connection when retrieving any open orders linked to the account.
Expand Down
14 changes: 6 additions & 8 deletions roboquant-questdb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,19 @@
<artifactId>roboquant</artifactId>
<groupId>org.roboquant</groupId>
</dependency>
<dependency>
<artifactId>roboquant</artifactId>
<groupId>org.roboquant</groupId>
<type>test-jar</type>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.questdb</groupId>
<artifactId>questdb</artifactId>
<version>8.1.0</version>
</dependency>

<dependency>
<groupId>org.roboquant</groupId>
<artifactId>roboquant</artifactId>
<version>3.0.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>

</dependencies>
<repositories>
<repository>
Expand Down
6 changes: 6 additions & 0 deletions roboquant-ta/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@
<artifactId>ta-lib</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<artifactId>roboquant</artifactId>
<groupId>org.roboquant</groupId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
Expand Down
22 changes: 0 additions & 22 deletions roboquant/src/main/kotlin/org/roboquant/common/Asset.kt
Original file line number Diff line number Diff line change
Expand Up @@ -148,28 +148,6 @@ data class Forex(override val symbol: String, override val currency: Currency) :
*/
fun Collection<Asset>.getBySymbol(symbol: String): Asset = first { it.symbol == symbol }

/**
* Find an asset based on its [symbols] name. Will return an empty list if no assets are matched.
*/
fun Collection<Asset>.findBySymbols(vararg symbols: String): List<Asset> = findBySymbols(symbols.asList())

/**
* Find an asset based on its [symbols] name. Will return an empty list if no assets are matched.
*/
fun Collection<Asset>.findBySymbols(symbols: Collection<String>): List<Asset> = filter { it.symbol in symbols }

/**
* Find all assets based on their [currencyCodes]. Returns an empty list if no matching assets can be found.
*/
fun Collection<Asset>.findByCurrencies(vararg currencyCodes: String): List<Asset> =
findByCurrencies(currencyCodes.asList())

/**
* Find all assets based on their [currencyCodes]. Returns an empty list if no matching assets can be found.
*/
fun Collection<Asset>.findByCurrencies(currencyCodes: Collection<String>): List<Asset> =
filter { it.currency.currencyCode in currencyCodes }

/**
* Get all unique symbols from the assets
*/
Expand Down
22 changes: 0 additions & 22 deletions roboquant/src/main/kotlin/org/roboquant/common/TimeSeries.kt
Original file line number Diff line number Diff line change
Expand Up @@ -235,28 +235,6 @@ class TimeSeries(val timeline: Timeline, val values: DoubleArray) : Iterable<Obs
}


/**
* Flatten a Map of TimeSeries to a single TimeSeries sorted by their time. If there is overlap in time between runs and
* [noOverlap] is set to true, the earlier run observations will be used and later runs observations that overlap will
* be ignored.
*/
fun Map<String, TimeSeries>.flatten(noOverlap: Boolean = true): TimeSeries {
// Optimized path for a map with only one entry
if (size == 1) return values.first()
val sortedTimeSeries = values.sortedBy { it.timeline.first() }
val result = mutableListOf<Observation>()
var last = Instant.MIN
for (timeSeries in sortedTimeSeries) {
for (entry in timeSeries) {
if (noOverlap && entry.time <= last) continue
result.add(entry)
last = entry.time
}

}
return TimeSeries(result)
}

/**
* Normalize all the timeseries in his map
*/
Expand Down
17 changes: 0 additions & 17 deletions roboquant/src/main/kotlin/org/roboquant/common/extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

package org.roboquant.common

import kotlinx.coroutines.delay
import org.hipparchus.stat.descriptive.moment.StandardDeviation
import org.roboquant.common.Config.EPS
import java.lang.Integer.max
Expand All @@ -28,8 +27,6 @@ import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.temporal.ChronoUnit
import kotlin.math.absoluteValue
import kotlin.math.ln

Expand All @@ -50,20 +47,6 @@ operator fun Instant.compareTo(timeframe: Timeframe): Int {
}
}

/**
* Delay until this time is reached
*/
suspend fun Instant.delayUntil() {
val now = Instant.now()
delay(now.until(this, ChronoUnit.MILLIS).coerceAtLeast(0L))
}

/**
* Get the instant as ZonedDateTime UTC
*/
fun Instant.toUTC(): ZonedDateTime = atZone(ZoneOffset.UTC)


fun Instant.sameDay(other: Instant, zoneId: ZoneId = ZoneOffset.UTC): Boolean {
val dt1 = LocalDate.ofInstant(this, zoneId)
val dt2 = LocalDate.ofInstant(other, zoneId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import kotlin.reflect.KClass
* @property remaining should any remaining actions be sent, default is true
*
*/
@Suppress("unused")
class AggregatorLiveFeed(
private val feed: LiveFeed,
private val aggregationPeriod: TimeSpan,
Expand Down
11 changes: 6 additions & 5 deletions roboquant/src/main/kotlin/org/roboquant/feeds/csv/CSVConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ data class CSVConfig(
var assetBuilder: AssetBuilder = StockBuilder()
) {


private val pattern by lazy { Pattern.compile(filePattern) }

private var isInitialized = false
Expand All @@ -75,11 +74,15 @@ data class CSVConfig(
return CSVConfig(
filePattern = ".*.txt",
timeParser = AutoDetectTimeParser(2),
assetBuilder = { name: String -> Stock(name.removeSuffix(".us.txt").replace('-', '.').uppercase(), Currency.USD) }
assetBuilder = { name: String ->
Stock(
name.removeSuffix(".us.txt").replace('-', '.').uppercase(),
Currency.USD
)
}
)
}


/**
* Returns a CSVConfig suited for parsing MT5 CSV files
*
Expand Down Expand Up @@ -210,8 +213,6 @@ data class CSVConfig(
return file.isFile && pattern.matcher(name).matches() && name !in fileSkip
}



/**
* Merge a config map into this CSV config
*
Expand Down
17 changes: 0 additions & 17 deletions roboquant/src/main/kotlin/org/roboquant/traders/FlexTrader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package org.roboquant.traders

import org.roboquant.brokers.Account
import org.roboquant.brokers.Position
import org.roboquant.brokers.exposure
import org.roboquant.common.*
import org.roboquant.feeds.Event
import org.roboquant.feeds.PriceItem
Expand Down Expand Up @@ -113,22 +112,6 @@ open class FlexTrader(
return SingleTrader()
}

/**
* Capital-based flex trader.
*/
fun capitalBased(
configure: FlexPolicyConfig.() -> Unit = {}
): FlexTrader {
class CapiltalBasedTrader : FlexTrader(configure) {
override fun amountPerOrder(account: Account): Amount {
val capital = account.positions.values.exposure + account.buyingPower
val amount = account.convert(capital)
return amount * config.orderPercentage
}
}
return CapiltalBasedTrader()
}

/**
* Return a FlexTrader that generates bracket orders, with the following characteristics:
* - a market order for entry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,3 @@ private class SignalShuffleTrader(private val trader: Trader, private val random
*/
fun Trader.shuffleSignals(random: Random = Config.random): Trader = SignalShuffleTrader(this, random)

/**
* Shuffle signals before processing them in the trader, avoiding favoring assets that appear always first in the
* actions of an event.
*
* @property trader
* @constructor Create empty Signal resolver
*/
private class SkipSymbolsTrader(private val trader: Trader, private val symbols: List<String>) : Trader by trader {

override fun create(signals: List<Signal>, account: Account, event: Event): List<Instruction> {
val newSignals = signals.filter { it.asset.symbol !in symbols }
return trader.create(newSignals, account, event)
}
}

/**
* Skip [symbols] that should not be converted into orders by removing them from the signals
*/
fun Trader.skipSymbols(vararg symbols: String): Trader = SkipSymbolsTrader(this, symbols.asList())



Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.roboquant.feeds

import org.roboquant.TestData
import org.roboquant.common.Amount
import org.roboquant.common.Stock
import kotlin.test.Test
import kotlin.test.assertContains
Expand All @@ -36,6 +37,9 @@ internal class PriceItemTest {
var price = p.getPrice()
assertEquals(9.5, price)

val amt = p.getPriceAmount()
assertEquals(Amount("USD", 9.5), amt)

price = p.getPrice("WEIGHTED")
assertEquals(9.25, price)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2020-2024 Neural Layer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.roboquant.traders

import org.roboquant.TestData
import org.roboquant.brokers.Account
import org.roboquant.common.*
import org.roboquant.feeds.Event
import org.roboquant.orders.MarketOrder
import org.roboquant.orders.Instruction
import org.roboquant.strategies.Signal
import java.time.Instant
import kotlin.test.Test
import kotlin.test.assertEquals

internal class CircuitBreakerTest {

private class MyTrader : Trader {
override fun create(signals: List<Signal>, account: Account, event: Event): List<Instruction> {
return listOf(
MarketOrder(Stock("A"), 10),
MarketOrder(Stock("B"), 10),
MarketOrder(Stock("C"), 10)
)
}

}

@Test
fun test() {
val account = TestData.usAccount()
val time = Instant.now()
val policy = CircuitBreaker(MyTrader(), 8, 1.hours)
var orders = policy.create(emptyList(), account, Event.empty(time))
assertEquals(3, orders.size)

orders = policy.create(emptyList(), account, Event.empty(time + 30.minutes))
assertEquals(3, orders.size)

orders = policy.create(emptyList(), account, Event.empty(time + 50.minutes))
assertEquals(0, orders.size)

orders = policy.create(emptyList(), account, Event.empty(time + 51.minutes))
assertEquals(0, orders.size)

orders = policy.create(emptyList(), account, Event.empty(time + 120.minutes))
assertEquals(3, orders.size)

}
}
Loading

0 comments on commit 55f61f0

Please sign in to comment.