POE: Ambiente de Simulação
O POE (Portfolio Optimization Env) é um ambiente de simulação para treinar agentes otimizadores de carteira de ações utilizando aprendizado por reforço. O ambiente é fácil de usar e segue os padrões do Gymnasium e, por isso, é integrável a diversas bibliotecas de algoritmos de aprendizado por reforço (como o stable baselines 3).
O POE faz uso da formulação estado da arte de aprendizado por reforço, tornando fácil para desenvolvedores e pesquisadores produzirem conhecimento e desenvolverem sistemas otimizadores de portfólio de alto desempenho.
Simulação
Em um ambiente de aprendizado por reforço, é necessário que a simulação seja capaz de, a cada instante de tempo, receber uma ação do agente, definir a recompensa recebida por concluir aquela ação e retornar ao agente uma recompensa, de modo que ele tente maximizá-la a longo prazo e para aprender a melhor política de ações a se seguir. No POE, esses três parâmetros são definidos como explicado a seguir.
Ações esperadas
A ação que um agente deve fazer para interagir com o ambiente é chamada de "vetor porfólio". Sendo um com N ações, o vetor portfólio possui tamanho N+1, pois representa a proporção de valor investido em cada um dos componentes da carteira. O primeiro valor do portfólio sempre se refere ao valor não investido em nada (ou seja, valor imediatamente disponível para o investidor) e os outros N elementos se referem aos outros componentes da carteira.
Dessa forma, em uma carteira com as ações PETR4, VALE3 e VIVT3, por exemplo, um vetor portfólio W = [0.1, 0.3, 0.5, 0.2] expressa que, naquele instante de tempo, a carteira possui 10% do seu valor não-investido e 30%, 50% e 20% do seu valor investido nos componentes PETR4, VALE3 e VIVT3 respectivamente.
Assim, o agente deve fazer continuamente o balanceamento da carteira de modo a aumentar o lucro a longo prazo.
Observações retornadas
Neste ambiente de simulação, há dois tipos diferentes de observação: uma que retorna somente a série temporal dos componentes da carteira e outra que inclui a última ação feita pelo agente (algo útil em alguns algoritmos).
Caso a observação contenha somente a série temporal das ações, uma matriz de dimensões (f, n, t) é retornado para o agente. "f" representa o número de features temporais utilizadas (como preço de abertura, fechamento, etc.), "n" representa o número de componentes do portfólio e "t" é a janela de tempo utilizada para definir as séries temporais.
Caso a observação inclua a última ação feita pelo agente, um dicionário será retornado com a seguinte forma:
❗É possível modificar o tipo de observação por meio do parâmetro return_last_action ao instanciar o ambiente.
Recompensas recebidas
O ambiente envia ao agente uma recompensa que é dada pelo logaritmo natural da razão entre o valor da carteira antes e depois do step de simulação. Assim, a recompensa é positiva em caso de lucro e negativa em caso de perdas financeiras. Além disso, ela possui valores próximos de zero.
Steps e episódios
No POE, o período definido por um step de simulação depende dos dados de entrada: se os dados tiverem valores diários de ações, por exemplo, um step de simulação calcula a variação do portfólio de um dia para o outro.
Já um episódio de simulação engloba todos os steps contidos nos dados de entrada: se eles contiverem 100 dias do preço das ações, por exemplo, um episódio será composto por 100 steps menos o tamanho da janela de tempo utilizada pelo agente (já que o balanceamento somente começará quando o agente tiver uma janela de tamanho definida).
Detalhes da simulação
Detalhes sobre a simulação implementada podem ser encontrados no artigo publicado no workshop brasileiro de IA em finanças, organizado pela Sociedade Brasileira de Computação (SBC). A imagem a seguir redireciona para a biblioteca digital da SBC.
Instalação
O ambiente faz parte da biblioteca FinRL-Meta, um repositório com diversos ambientes de simulação para aprendizado por reforço. Por isso, para instalar o POE, basta clonar o repositório e acessar o ambiente, que está na pasta FinRL-Meta/meta/env_portfolio_optimization/
Em breve, o ambiente será adicionado ao FinRL, biblioteca que contém, não só ambientes, mas agentes de aprendizado por reforço. A adição do POE ainda está em processo de revisão.
Utilizando o POE
Preparando os dados
Antes de utilizar o POE, é necessário ter em mãos os dados financeiros que serão utilizados na simulação. Esses dados devem estar em forma de Pandas Dataframe, e devem ter mais ou menos o seguinte formato:
date high low close tic
0 2020-12-23 0.157414 0.127420 0.136394 ADA-USD
1 2020-12-23 34.381519 30.074295 31.097898 BNB-USD
2 2020-12-23 24024.490234 22802.646484 23241.345703 BTC-USD
3 2020-12-23 0.004735 0.003640 0.003768 DOGE-USD
4 2020-12-23 637.122803 560.364258 583.714600 ETH-USD
... ... ... ... ... ...
O nome das colunas é irrelevante pois, durante a instanciação do ambiente, é possível explicitar os nomes que serão utilizados. Apesar disso, é importante que o dataframe possua uma coluna de datas e outra com o nome da ação, moeda, etc. É necessário que, para todos os dias existentes no dataframe, existam dados de todas os componentes do portfólio.
Instanciando o ambiente
Uma vez tendo os dados em mãos, iniciar o ambiante é extremamente fácil. Basta utilizar a classe PortfolioOptimizationEnv e definir seus múltiplos parâmetros, como no exemplo abaixo, em que os dados estão na variável df_portfolio.
Os únicos argumentos obrigatórios são o dataframe de dados e o valor inicial do portfólio, que são necessários para que a simulação consiga ocorrer. Mas, é possível utilizar outros argumentos, como foi feito no exemplo anterior. Alguns argumentos interessantes são:
comission_fee_pct: define a comissão percentual de taxa de comissão (recomenda-se utilizar um valor entre 0 e 1).
normalize_df: define o método que é utilizado durante a normalização de dados.
features: nome das colunas que devem ser utilizadas como features de dados.
time_window: tamanho da janela de tempo utilizada para retornar as séries temporais que definem os estados do agente.
return_last_action: parâmetro que define se o ambiente retornará, na observação do agente, a última ação.
Diversos outros parâmetros encontram-se documentados no código do ambiente.
Resetando o ambiente
Antes de iniciar a simulação, é preciso resetar o ambiente. Isso é necessário pois considera-se que um episódio ocorre enquanto o ambiente percorre o período de dados do dataframe e, ao chegar ao final, o ambiente fica em estado terminal até que um reset ocorra. Para fazer um reset, basta rodar:
A variável retornada se refere à observação inicial do agente, antes de ocorrer qualquer passagem de tempo no episódio.
❗Observação
Note que esta interface é a antiga interface do Gym, predecessor do Gymnasium. Alguns algoritmos (como por exemplo, do stable baselines 3), podem utilizar a nova interface que retorna, além da obs, uma variável info, que é um dicionário com informações sobre o início da simulação. Para utilizar esse nova interface, use o parâmetro new_gym_api=True na instanciação do ambiente. Iremos, eventualmente, fazer a nova interface ser a padrão.
Para mais detalhes sobre a mudança de API, visite este site.
Executando um step de simulação
Para executar um step, basta chamar a função chamada step, passando a ação que deseja ser feita, como em todos os ambientes que uitilizam o padrão do Gymnasium.
As variáveis retornadas são a observação do novo estado do agente após a simulação, sua recompensa recebida, se o estado foi final ou não e um dicionário com informações gerais da simulação feita.
❗Observação
Note que esta interface é a antiga interface do Gym, predecessor do Gymnasium. Alguns algoritmos (como por exemplo, do stable baselines 3), podem utilizar a nova interface que retorna, além dessas 4, uma variável truncated, que define se o episódio terminou por alcançar um tempo máximo. Para utilizar esse nova interface, use o parâmetro new_gym_api=True na instanciação do ambiente. Iremos, eventualmente, fazer a nova interface ser a padrão.
Para mais detalhes sobre a mudança de API, visite este site.
Exemplos
O código a seguir implementa a estratégia uniform buy and hold (comprar ações e segurá-las indefinidamente) aplicadas ao POE. Considere que a variável df_portfolio existe e foi previamente definida.
Repare como a ação é definida: criamos um array com PORTFOLIO_SIZE+1 elementos: o primeiro valor é 0 pois não queremos nenhum dinheiro sem investimento e os outros valores são razões iguais, indicando que investiu-se igualmente nas ações.
Um outro exemplo mais complexo, fazendo uso de um agente de aprendizado por reforço profundo pode ser encontrado aqui.