Skip to content

Commit

Permalink
Merge pull request #17 from pagh2322/feat/11
Browse files Browse the repository at this point in the history
Feat/11
  • Loading branch information
pagh2322 authored May 1, 2024
2 parents 461a08a + 1709d91 commit af77446
Show file tree
Hide file tree
Showing 99 changed files with 3,485 additions and 1,037 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jacocoTestCoverageVerification {
minimum = 0.75
}

excludes = ['*.*Controller', '*.*Repository', '*.advice.*', '*.dto.*', '*.config.*', '*.domain.*', '*.support.*', '*.AuthService']
excludes = ['*.*Repository', '*.dto.*', '*.global.*', '*.auth.*']
}
}
}
1 change: 1 addition & 0 deletions src/main/java/org/mockInvestment/auth/api/AuthApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ public class AuthApi {
public ResponseEntity<AuthInfo> oauthLoginInfo(@Login AuthInfo authInfo) {
return ResponseEntity.ok(authInfo);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Service
@Transactional
@RequiredArgsConstructor
Expand All @@ -40,17 +38,15 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic
}

private Member getOrCreateMember(OAuth2UserAttributes oAuth2UserAttributes) {
Member member = memberRepository.findByUsername(oAuth2UserAttributes.getUsername())
return memberRepository.findByUsername(oAuth2UserAttributes.getUsername())
.orElseGet(() -> {
Member newMember = Member.builder()
.role("ROLE_USER")
.email(oAuth2UserAttributes.getEmail())
.username(oAuth2UserAttributes.getUsername())
.build();
return memberRepository.save(newMember);
});
member.updateEMail(oAuth2UserAttributes.getEmail());
member.updateName(oAuth2UserAttributes.getName());
return member;
}

}
6 changes: 1 addition & 5 deletions src/main/java/org/mockInvestment/auth/dto/AuthInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,24 @@ public class AuthInfo {

private final String role;

private final String name;

private final String username;

public AuthInfo(Long id, String role, String name, String username) {
public AuthInfo(Long id, String role, String username) {
this.id = id;
this.role = role;
this.name = name;
this.username = username;
}

public AuthInfo(Member member) {
id = member.getId();
role = member.getRole();
name = member.getName();
username = member.getUsername();
}

public AuthInfo() {
id = null;
role = null;
name = null;
username = null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ public String getAuthority() {

@Override
public String getName() {
return authInfo.getName();
return authInfo.getUsername();
}
}
50 changes: 50 additions & 0 deletions src/main/java/org/mockInvestment/backTest/api/BackTestApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.mockInvestment.backTest.api;

import lombok.RequiredArgsConstructor;
import org.mockInvestment.backTest.application.BackTestCrossStrategyService;
import org.mockInvestment.backTest.application.BackTestRSIStrategyService;
import org.mockInvestment.backTest.dto.request.CrossStrategyRequest;
import org.mockInvestment.backTest.dto.request.RSIStrategyRequest;
import org.mockInvestment.backTest.dto.response.BackTestResultResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDate;

@RestController
@RequiredArgsConstructor
@RequestMapping("/back_test")
public class BackTestApi {

private final BackTestRSIStrategyService backTestRSIStrategyService;

private final BackTestCrossStrategyService backTestCrossStrategyService;


@GetMapping("/rsi")
public ResponseEntity<BackTestResultResponse> backTestUsingRSIStrategy(
@RequestParam("code") String stockCode,
@RequestParam("start") LocalDate startDate,
@RequestParam("end") LocalDate endDate,
@RequestParam("buyRSI") double buyRSI,
@RequestParam("sellRSI") double sellRSI,
@RequestParam("amount") double amount
) {
RSIStrategyRequest request = new RSIStrategyRequest(stockCode, startDate, endDate, buyRSI, sellRSI, amount);
BackTestResultResponse response = backTestRSIStrategyService.runTest(request);
return ResponseEntity.ok(response);
}

@GetMapping("/cross")
public ResponseEntity<BackTestResultResponse> backTestUsingCrossStrategy(
@RequestParam("code") String stockCode,
@RequestParam("start") LocalDate startDate,
@RequestParam("end") LocalDate endDate,
@RequestParam("amount") double amount
) {
CrossStrategyRequest request = new CrossStrategyRequest(true, true, stockCode, startDate, endDate, amount);
BackTestResultResponse response = backTestCrossStrategyService.runTest(request);
return ResponseEntity.ok(response);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.mockInvestment.backTest.application;

import lombok.RequiredArgsConstructor;
import org.mockInvestment.backTest.dto.request.CrossStrategyRequest;
import org.mockInvestment.backTest.dto.response.BackTestResultResponse;
import org.mockInvestment.backTest.dto.response.BackTestTradeHistory;
import org.mockInvestment.stockPrice.application.StockPriceCandleFindService;
import org.mockInvestment.stockPrice.domain.StockPriceCandle;
import org.mockInvestment.stockPrice.repository.StockPriceCandleRepository;
import org.mockInvestment.stockPrice.util.PeriodExtractor;
import org.mockInvestment.stockTicker.domain.StockTicker;
import org.mockInvestment.stockTicker.exception.StockTickerNotFoundException;
import org.mockInvestment.stockTicker.repository.StockTickerRepository;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class BackTestCrossStrategyService {

private final StockTickerRepository stockTickerRepository;

private final StockPriceCandleRepository stockPriceCandleRepository;

private final StockPriceCandleFindService stockPriceCandleFindService;


public BackTestResultResponse runTest(CrossStrategyRequest request) {
StockTicker stockTicker = stockTickerRepository.findByCode(request.stockCode())
.orElseThrow(StockTickerNotFoundException::new);
List<BackTestTradeHistory> histories = new ArrayList<>();
LocalDate startDate = request.startDate();
while (startDate.isBefore(request.endDate())) {
PeriodExtractor periodExtractor = new PeriodExtractor(startDate, "6m");
List<StockPriceCandle> stockPriceCandles = stockPriceCandleFindService.findStockPriceCandles(stockTicker, periodExtractor);

double currentPrice = stockPriceCandles.get(stockPriceCandles.size() - 1).getClose();

if (histories.isEmpty()) {
histories.add(BackTestTradeHistory.of(true, currentPrice, request.amount(), null, startDate));
startDate = getNextMarketDate(startDate);
continue;
}

double[] macd = TechnicalIndicatorCalculator.calculateMACD(stockPriceCandles);
double[] signalLine = TechnicalIndicatorCalculator.calculateSignalLine(macd);

BackTestTradeHistory lastOrder = histories.get(histories.size() - 1);
double amount = calcAmount(lastOrder.amount(), lastOrder.price(), currentPrice);

double currentMACD = macd[macd.length - 2];
double currentSignalLine = signalLine[signalLine.length - 2];
double previousMACD = macd[macd.length - 3];
double previousSignalLine = signalLine[signalLine.length - 3];

if (currentMACD > currentSignalLine && previousMACD < previousSignalLine) {
if (!lastOrder.buy())
histories.add(BackTestTradeHistory.of(true, currentPrice, amount, "Golden", startDate));
} else if (currentMACD < currentSignalLine && previousMACD > previousSignalLine) {
if (lastOrder.buy())
histories.add(BackTestTradeHistory.of(false, currentPrice, amount, "Dead", startDate));
}
startDate = getNextMarketDate(startDate);
}
return new BackTestResultResponse(histories);
}

private double calcAmount(double previousAmount, double previousPrice, double currentPrice) {
return previousAmount * (currentPrice / previousPrice);
}

private LocalDate getNextMarketDate(LocalDate previousDate) {
List<LocalDate> dates = stockPriceCandleRepository.findCandidateDates(previousDate, PageRequest.of(0, 2));
return dates.get(1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.mockInvestment.backTest.application;

import lombok.RequiredArgsConstructor;
import org.mockInvestment.backTest.dto.request.RSIStrategyRequest;
import org.mockInvestment.backTest.dto.response.BackTestResultResponse;
import org.mockInvestment.backTest.dto.response.BackTestTradeHistory;
import org.mockInvestment.stockPrice.application.StockPriceCandleFindService;
import org.mockInvestment.stockPrice.domain.StockPriceCandle;
import org.mockInvestment.stockPrice.repository.StockPriceCandleRepository;
import org.mockInvestment.stockPrice.util.PeriodExtractor;
import org.mockInvestment.stockTicker.domain.StockTicker;
import org.mockInvestment.stockTicker.exception.StockTickerNotFoundException;
import org.mockInvestment.stockTicker.repository.StockTickerRepository;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class BackTestRSIStrategyService {

private final StockTickerRepository stockTickerRepository;

private final StockPriceCandleRepository stockPriceCandleRepository;

private final StockPriceCandleFindService stockPriceCandleFindService;


public BackTestResultResponse runTest(RSIStrategyRequest request) {
StockTicker stockTicker = stockTickerRepository.findByCode(request.stockCode())
.orElseThrow(StockTickerNotFoundException::new);
List<BackTestTradeHistory> histories = new ArrayList<>();
LocalDate startDate = request.startDate();
while (startDate.isBefore(request.endDate())) {
PeriodExtractor periodExtractor = new PeriodExtractor(startDate, "6m");
List<StockPriceCandle> stockPriceCandles = stockPriceCandleFindService.findStockPriceCandles(stockTicker, periodExtractor);
double rsi = TechnicalIndicatorCalculator.calculateRSI(stockPriceCandles);
double currentPrice = stockPriceCandles.get(stockPriceCandles.size() - 1).getClose();

if (histories.isEmpty()) {
histories.add(BackTestTradeHistory.of(true, currentPrice, request.amount(), rsi, startDate));
startDate = getNextMarketDate(startDate);
continue;
}

BackTestTradeHistory lastOrder = histories.get(histories.size() - 1);
double amount = calcAmount(lastOrder.amount(), lastOrder.price(), currentPrice);
if (rsi >= request.sellRSI()) { // should sell
if (lastOrder.buy())
histories.add(BackTestTradeHistory.of(false, currentPrice, amount, rsi, startDate));
}
else if (rsi <= request.buyRSI()) { // should buy
if (!lastOrder.buy())
histories.add(BackTestTradeHistory.of(true, currentPrice, amount, rsi, startDate));
}
startDate = getNextMarketDate(startDate);
}
return new BackTestResultResponse(histories);
}

private double calcAmount(double previousAmount, double previousPrice, double currentPrice) {
return previousAmount * (currentPrice / previousPrice);
}

private LocalDate getNextMarketDate(LocalDate previousDate) {
List<LocalDate> dates = stockPriceCandleRepository.findCandidateDates(previousDate, PageRequest.of(0, 2));
return dates.get(1);
}

}
Loading

0 comments on commit af77446

Please sign in to comment.