Possível nova maneira de randomizar dados com %change em vez de %ATR
5 respostas
bentra
3 anos atrás #267915
Como aqui: https://roadmap.strategyquant.com/tasks/sq4_7233
e aqui: https://roadmap.strategyquant.com/tasks/sq4_7350
A maneira atual não é perfeita e algumas estratégias podem explorar o algoritmo de randomização de dados históricos, enquanto outras sofrem com o viés desse teste. Acredito que isso se deva à maneira como o ATR é usado no algoritmo, combinado com o fato de que a nova posição aleatória sempre se baseia no próximo tick de dados original (que terá um efeito extra de reversão à média e um x% de ATR mais alto aumentará a volatilidade).
Nesse novo método, eu randomizo o % da mudança de preço em vez do % do ATR e permito que o preço defina um novo caminho para que cada tick seja baseado no último tick dos dados randomizados (permitindo que o preço se afaste lentamente dos dados originais, eliminando a reversão excessiva ao efeito médio). Isso deve manter a volatilidade durante a randomização dos dados, desde que a alteração do % seja razoável.
Abri este tópico para discussão e teste. No momento, trata-se de um trabalho em andamento. Não tenho muita familiaridade com Java, portanto, poderia me ajudar com o código e com os testes.
Tive tempo de trabalhar nisso hoje e aqui está o que tenho até agora, mas você pode querer verificar se há novas versões mais adiante neste tópico, à medida que progredimos e publicamos novas versões.
bentra
3 anos atrás #267956
Parece que, desta vez, corrigi corretamente o erro do primeiro tique
/*
* Copyright (c) 2017-2018, StrategyQuant - Todos os direitos reservados.
*
* O código neste arquivo foi criado de boa-fé, garantindo que está correto e faz o que deveria.
* Se você encontrou um bug neste código OU tem uma sugestão de melhoria OU deseja incluir
* seu próprio trecho de código em nossa biblioteca padrão, entre em contato conosco em:
* https://roadmap.strategyquant.com
*
* Este código pode ser usado somente em produtos StrategyQuant.
* Todo proprietário de uma licença válida (gratuita, de teste ou comercial) de qualquer produto StrategyQuant
* tem permissão para usar, copiar, modificar ou fazer trabalhos derivados desse código livremente, sem limitações,
* para ser usado em todos os produtos StrategyQuant e compartilhar suas modificações ou trabalhos derivados
* com a comunidade StrategyQuant.
*
* O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA,
* INCLUINDO, MAS NÃO SE LIMITANDO A, GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO
* FINALIDADE ESPECÍFICA E NÃO VIOLAÇÃO. EM NENHUMA HIPÓTESE OS AUTORES SERÃO RESPONSÁVEIS POR QUALQUER REIVINDICAÇÃO, DANO
* OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ATO ILÍCITO OU DE OUTRA FORMA, DECORRENTE DE,
* DECORRENTES DE, FORA DE OU EM CONEXÃO COM O SOFTWARE OU COM O USO OU OUTRAS NEGOCIAÇÕES COM O SOFTWARE.
*
*/
package SQ.MonteCarlo.Retest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.datalib.consts.Precisions;
import com.strategyquant.tradinglib.*;
@ClassConfig(name="Randomizar dados do histórico", display="Randomizar dados do histórico v2.0, com alteração máxima de preço #MaxChange# % de PRICE")
@Help("<b>Nota!</b>Se você escolher essa opção, os testes de robustez serão testados com a precisão do período de tempo selecionado, enquanto a estratégia original será testada com a precisão configurada.<br/>Isso pode causar diferenças nos resultados entre a estratégia original e as simulações devido à precisão diferente.<br/>Para evitar isso, use a precisão do período de tempo selecionado em Setings : Data.")
classe pública RandomizeHistoryData2 extends MonteCarloRetest {
logger final estático público Logger = LoggerFactory.getLogger(RandomizeHistoryData2.class);
//@Parameter(name="Probability change price", defaultValue="20", minValue=1, maxValue=100, step=1)
//public int Probability;
@Parameter(name="Max change price", defaultValue="10", minValue=1, maxValue=100, step=1)
public int MaxChange;
private int barsProcessed = 0;
private double atrValue = 0;
private int atrPeriod = 14;
private int relativeMaxChange = -1;
//bendedit: precisamos de algumas variáveis persistentes para que possamos rastrear o preço e permitir que ele se afaste dos dados originais
private double lastbid=0;
private double lastorgbid=0;
private long lastticktime=0;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
public RandomizeHistoryData2() {
super(MonteCarloTestTypes.ModifyData);
}
//------------------------------------------------------------------------
public void modifyData(IRandomGenerator rng, TickEvent tickEvent, double globalATR) {
//double dblProbability = ((double) Probability/ 100.0d);
//se(rng.probability(dblProbability)) {
// bendedit: I don't see a point in probability of change, lets just always change every tick, it will be much smooth more now that we turfed ATR from the equation.
// devemos alterar esse preço
double ask = tickEvent.getAsk();
double bid = tickEvent.getBid();
double spread = ask - bid;
double tickorgchange=0;
long currentticktime = tickEvent.getTime();
//bendedit: verifica se é o primeiro tick; caso contrário, define a alteração do tick original.
if (lastticktime <= currentticktime && lastticktime!=0) {
//bendedit: calculate the price change from last original tick to the current tick from original data
tickorgchange=bid-lastorgbid;
//debug("MC price randomizer", "tickorgchange is: "+tickorgchange);
//debug("MC price randomizer", "time is: "+currentticktime);
//debug("MC price randomizer", "last time is: "+lastticktime);
//debug("MC price randomizer", "EOL");
} else { //bendedit: in case of first tick there is no change.
lastbid=bid;
tickorgchange=0;
}
//bendedit:set last original data bid in to variable before we change bid, we only need it to calculate the price change next time.
lastorgbid=bid;
//bendedit:store the ticktime.
lastticktime = currentticktime;
int change;
if(relativeMaxChange <= 0) {
change = rng.nextInt(MaxChange);
} else {
change = rng.nextInt(relativeMaxChange);
}
double dblChange = ((double) change)/ 10000.0d;
//bendedit: Modding every tick and allowing price to move far away from original data therefore we need to use much smaller adjustments.
//bendedit: I chose a percent of a percent
//bendedit: changed from using ATR to just use tick price change of original data.
double priceChange = tickorgchange * dblChange;
//bendedit: set the working bid relative to the last bid instead of itself
//bid = (rng.nextInt(2) == 0 ? bid + priceChange : bid - priceChange);
bid = (rng.nextInt(2) == 0 ? lastbid + tickorgchange + priceChange : lastbid + tickorgchange - priceChange);
tickEvent.setBid(bid);
tickEvent.setAsk(bid + spread);
//bendedit:set last bid in to variable for next time.
lastbid = bid;
//}
}
//------------------------------------------------------------------------
public void initSettings(SettingsMap settings) {
super.initSettings(settings);
// compute relative Max Change according to chart TF and precision
ChartSetup chartSetup = (ChartSetup) settings.get(SettingsKeys.BacktestChart);
if(chartSetup != null) {
int testPrecision = chartSetup.getTestPrecision();
if(testPrecision == Precisions.SelectedTF) {
// do nothing for selected TF precision
relativeMaxChange = MaxChange;
return;
}
// it is higher precision, set MaxChange to 1/3 of the value
// because the change is applied o every minute bar / tick we have to lower the MaxChange
// so that the resulting full bar in target timeframe (for example H1) isn't changed too much
//bendedit: Hopefully we don't need this adjustment anymore since we aren't using globalATR which is inflated by higher timeframes. deviding by 3 arbitrarily was suspect anyways. If we still need to adjust, I'll hopefully find a better way.
//bendedit: Now that we are doing change % instead of atr %, we may not need any further adjustments relative to precision or TF. Turned off this equalizer for now.
//relativeMaxChange = MaxChange / 3;
relativeMaxChange = MaxChange;
if(relativeMaxChange <= 0) {
relativeMaxChange = 1;
}
}
}
}
bentra
3 anos atrás #267958
Este funciona no b130
/*
* Copyright (c) 2017-2018, StrategyQuant - Todos os direitos reservados.
*
* O código neste arquivo foi criado de boa-fé, garantindo que está correto e faz o que deveria.
* Se você encontrou um bug neste código OU tem uma sugestão de melhoria OU deseja incluir
* seu próprio trecho de código em nossa biblioteca padrão, entre em contato conosco em:
* https://roadmap.strategyquant.com
*
* Este código pode ser usado somente em produtos StrategyQuant.
* Todo proprietário de uma licença válida (gratuita, de teste ou comercial) de qualquer produto StrategyQuant
* tem permissão para usar, copiar, modificar ou fazer trabalhos derivados desse código livremente, sem limitações,
* para ser usado em todos os produtos StrategyQuant e compartilhar suas modificações ou trabalhos derivados
* com a comunidade StrategyQuant.
*
* O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA,
* INCLUINDO, MAS NÃO SE LIMITANDO A, GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM DETERMINADO
* FINALIDADE ESPECÍFICA E NÃO VIOLAÇÃO. EM NENHUMA HIPÓTESE OS AUTORES SERÃO RESPONSÁVEIS POR QUALQUER REIVINDICAÇÃO, DANO
* OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, ATO ILÍCITO OU DE OUTRA FORMA, DECORRENTE DE,
* DECORRENTES DE, FORA DE OU EM CONEXÃO COM O SOFTWARE OU COM O USO OU OUTRAS NEGOCIAÇÕES COM O SOFTWARE.
*
*/
package SQ.MonteCarlo.Retest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.strategyquant.lib.*;
import com.strategyquant.datalib.*;
import com.strategyquant.datalib.consts.Precisions;
import com.strategyquant.tradinglib.*;
@ClassConfig(name="Randomize history data", display="Randomize history data v2.0, with max change #MaxChange# % of TICK PRICE CHANGES")
@Help("<b>Nota!</b>Se você escolher essa opção, os testes de robustez serão testados com a precisão do período de tempo selecionado, enquanto a estratégia original será testada com a precisão configurada.<br/>Isso pode causar diferenças nos resultados entre a estratégia original e as simulações devido à precisão diferente.<br/>Para evitar isso, use a precisão do período de tempo selecionado em Setings : Data.")
classe pública RandomizeHistoryData2 extends MonteCarloRetest {
logger final estático público Logger = LoggerFactory.getLogger(RandomizeHistoryData2.class);
//@Parameter(name="Probability change price", defaultValue="20", minValue=1, maxValue=100, step=1)
//public int Probability;
@Parameter(name="Max change price", defaultValue="10", minValue=1, maxValue=100, step=1)
public int MaxChange;
private int barsProcessed = 0;
private double atrValue = 0;
private int atrPeriod = 14;
private int relativeMaxChange = -1;
//bendedit: precisamos de algumas variáveis persistentes para que possamos rastrear o preço e permitir que ele se afaste dos dados originais
private double lastbid=0;
private double lastorgbid=0;
private long lastticktime=0;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
public RandomizeHistoryData2() {
super(MonteCarloTestTypes.ModifyData);
}
//------------------------------------------------------------------------
public void modifyData(IRandomGenerator rng, TickEvent tickEvent, double globalATR) {
//double dblProbability = ((double) Probability/ 100.0d);
//se(rng.probability(dblProbability)) {
// bendedit: I don't see a point in probability of change, lets just always change every tick, it will be much smooth more now that we turfed ATR from the equation.
// devemos alterar esse preço
double ask = tickEvent.getAsk();
double bid = tickEvent.getBid();
double spread = ask - bid;
double tickorgchange=0;
long currentticktime = tickEvent.getTime();
//bendedit: verifica se é o primeiro tick; caso contrário, define a alteração do tick original.
if (lastticktime <= currentticktime && lastticktime!=0) {
//bendedit: calculate the price change from last original tick to the current tick from original data
tickorgchange=bid-lastorgbid;
//debug("MC price randomizer", "tickorgchange is: "+tickorgchange);
//debug("MC price randomizer", "time is: "+currentticktime);
//debug("MC price randomizer", "last time is: "+lastticktime);
//debug("MC price randomizer", "EOL");
} else { //bendedit: in case of first tick there is no change.
lastbid=bid;
tickorgchange=0;
}
//bendedit:set last original data bid in to variable before we change bid, we only need it to calculate the price change next time.
lastorgbid=bid;
//bendedit:store the ticktime.
lastticktime = currentticktime;
int change;
if(relativeMaxChange <= 0) {
change = rng.nextInt(MaxChange);
} else {
change = rng.nextInt(relativeMaxChange);
}
double dblChange = ((double) change)/ 10000.0d;
//bendedit: Modding every tick and allowing price to move far away from original data therefore we need to use much smaller adjustments.
//bendedit: I chose a percent of a percent
//bendedit: changed from using ATR to just use tick price change of original data.
double priceChange = tickorgchange * dblChange;
//bendedit: set the working bid relative to the last bid instead of itself
//bid = (rng.nextInt(2) == 0 ? bid + priceChange : bid - priceChange);
bid = (rng.nextInt(2) == 0 ? lastbid + tickorgchange + priceChange : lastbid + tickorgchange - priceChange);
tickEvent.setBid(bid);
tickEvent.setAsk(bid + spread);
//bendedit:set last bid in to variable for next time.
lastbid = bid;
//}
}
//------------------------------------------------------------------------
public void initSettings(SettingsMap settings) {
super.initSettings(settings);
// compute relative Max Change according to chart TF and precision
ChartSetup chartSetup = (ChartSetup) settings.get(SettingsKeys.BacktestChart);
if(chartSetup != null) {
int testPrecision = chartSetup.getTestPrecision();
if(testPrecision == Precisions.SelectedTF) {
// do nothing for selected TF precision
relativeMaxChange = MaxChange;
return;
}
// it is higher precision, set MaxChange to 1/3 of the value
// because the change is applied o every minute bar / tick we have to lower the MaxChange
// so that the resulting full bar in target timeframe (for example H1) isn't changed too much
//bendedit: Hopefully we don't need this adjustment anymore since we aren't using globalATR which is inflated by higher timeframes. deviding by 3 arbitrarily was suspect anyways. If we still need to adjust, I'll hopefully find a better way.
//bendedit: Now that we are doing change % instead of atr %, we may not need any further adjustments relative to precision or TF. Turned off this equalizer for now.
//relativeMaxChange = MaxChange / 3;
relativeMaxChange = MaxChange;
if(relativeMaxChange <= 0) {
relativeMaxChange = 1;
}
}
}
//------------------------------------------------------------------------
/**
* Clones this MC retest object
*
* @return the clone
* @throws Exception the exception
*/
@Override
public RandomizeHistoryData2 getClone() throws Exception {
RandomizeHistoryData2 mc = new RandomizeHistoryData2();
mc.MaxChange = this.MaxChange;
return mc;
}
}
clonex / Ivan Hudec
3 anos atrás #267976
Oi Bendex. Vamos testá-lo em alguns milhares de estratégias e publicaremos os resultados aqui. Obrigado por esse snippet,
bentra
3 anos atrás #267979
Muito obrigado, mas estou preocupado com as possíveis diferenças em diferentes mercados, talvez devido ao arredondamento. Além disso, os efeitos de diferentes cronogramas e precisões.
bentra
3 anos atrás #268127
A nova versão está aqui:
https://roadmap.strategyquant.com/tasks/sq4_7233
-Possíveis erros de arredondamento corrigidos
-configuração padrão para 40%
Qualquer ajuda nos testes é bem-vinda. Publique quaisquer configurações/estratos problemáticos nesse tíquete.
Visualizando 5 respostas - 1 até 5 (de um total de 5)