시뻘건 개발 도전기

#3. 코인 자동 매매 프로그램 만들기 본문

프로젝트/토이프로젝트

#3. 코인 자동 매매 프로그램 만들기

시뻘건볼때기 2022. 2. 7. 17:23
반응형
※ 본 '코인 자동 매매 프로그램 만들기' 시리즈 포스팅은 개인적인 학습용으로 개발하게 되는 프로그램입니다.
투자의 책임은 투자자 본인에게 있음을 알려드립니다.

이번 포스팅에서는 scheduling에 대해 설명한다.

 

내가 배치로 실행할 scheduler는 아래와 같다.

  1. Alarm class : 내가 투자를 하면서 가장 내 자신이 한심하다고 느낀 것이 하루종일 앱만 보고 있는 나의 모습이었다. 그래서 앱을 보지 않게 하기 위해 일정한 시간 간격으로 나의 포트폴리오 상태를 slack을 통해 알람을 발송한다.
  2. Buy class : 말 그래도 매수만을 담당한다. 그러나 내가 사지 않은 새로운 코인만을 매수한다. (추가매수 x)
  3. DailyVisual class : 나의 포트폴리오에 대해서 매일 9시에 시각화한다. 처음엔 그래프로 출력(output)해서 png 파일을 생성하려 했으나, 파일이 순식간에 많아지고 리소스관리, 서버 장비 메모리가 그렇게 좋지 못했기 때문에 엑셀을 사용했다. 엑셀을 사용해서 내가 어떤 코인을 샀는데 손/이익율이 얼마나 되는지 출력한다.
  4. ReBuy class : 내가 가지고 있는 코인의 가격이 일정 퍼센트 손실이 되면 추가 매수를 담당한다.
  5. Sell class : 매도만을 담당한다. 나중에 코드를 보며 설명하겠지만 분할 매도 기능이 있으나, 나는 전량매도로 사용한다.
  6. SignCheck class : 코인을 주문을 넣었다고 해서 바로 매수/매도가 되는 것이 아니기 때문에 주문이 체결이 되었는지 일정한 시간 간격으로 체크하여 결과에 반영한다.
  7. UpbitInfo class : 업비트에서 제공하는 기본 정보들을 하루에 한 번 메모리에 올려두고 사용한다. 예를 들어 마켓별 주문 가능 정보는 굳이 매번 호출하여 받아올 필요가 없기 때문에 내 메모리에 올려두고 사용하는 것이다. 배치로 돌린 이유는 가끔 새로운 코인이 상장되거나 폐지가 되기 때문이다. (포스팅을 하면서 발견한건데 패키지 리펙토링을 해야겠다.)

 

업비트 API document 참고

 

업비트 개발자 센터

업비트 Open API 사용을 위한 개발 문서를 제공 합니다.업비트 Open API 사용하여 다양한 앱과 프로그램을 제작해보세요.

docs.upbit.com

 

 

/*
 * 주기적으로 현재 월렛 상황 실시간 알림
 */
@Component
@Slf4j
public class Alarm {
    private NonAuthAPI nonAuthAPI;

    @Autowired
    public void setNonAuthAPI(NonAuthAPI nonAuthAPI) {
        this.nonAuthAPI = nonAuthAPI;
    }

    @Scheduled(cron = "{알람_크론_정규식}")
    public void alarm() {
        MDC.put(SchedulerConfig.loggingID, this.getClass().getSimpleName());
        try {
            StringBuilder message = new StringBuilder();
            List<Map<String,String>> realTimeWallet = UpbitInfo.getMyCoinList();

            for(Map<String,String> realTimeCoin : realTimeWallet) {
                try {
                    String coin = realTimeCoin.get(APIKeyConst.COIN);
                    if(UpbitConst.IGNORE_COIN.contains(coin)) {
                        continue;
                    }
                    Map<String,String> realTimeMarket = nonAuthAPI.getCoinDetail(coin).get(0);
                    double rateOfReturn = Calculate.getRateOfReturn(realTimeCoin, realTimeMarket);
                    message.append(coin).append(" : ").append(rateOfReturn).append("\r\n");
                } catch (Exception e) {
                    SlackClient.sendSlack(e.toString());
                }
            }

            SlackClient.sendSlack(message.toString());
        } catch (Exception e) {
            log.error ("exception msg", e);
            SlackClient.sendSlack(e.toString());
        }
    }
}

동시에 몇 개의 스레드가 돌아가는지에 따라 다르겠지만 동시에 여러 스레드가 실행되면 로그를 볼때 복잡하고 문제가 발생했을 때 파악하기 어렵기 때문에 MDC를 사용해서 어떤 스레드인지 명확하게 로깅하였다. (로깅 설정 시 스레드 명의 prefix는 붙일 수 있지만 그것으로 부족하다고 판단)

간혹 어떤 코인을 가지고 있을 때 특정 코인을 에어드랍하는 경우가 있는데, 정말 쪼~~~~~~금 줘서 매도할 수 있는 최소 금액도 안된다. 그런 경우를 대비해서 UpbitConst.IGNORE_COIN로 관리하게 된다. 매도/알람은 발생시키지 않도록 한다.

알람은 어떤 코인이 어떤 손/이익율을 가지고 있는지 slcak으로 알려준다.

 

@Slf4j
public class SlackClient {
    private static final String SLACK_WEBHOOK_URL = "https://hooks.slack.com/services/**/*";
    private static final String CONTENT_TYPE = "application/json";
    private static final Map<String, String> HEADER = new HashMap<String, String>() {{
        put("Content-type", CONTENT_TYPE);
    }};

    public static void sendSlack(String message) {
        if(Objects.isNull(message) || message.length() == 0) {
            return;
        }

        log.info(message);

        try {
            String messageFormat = "{'text' : '#message'}";
            String response = HttpClient.sendPost(SLACK_WEBHOOK_URL, HEADER, messageFormat.replaceAll("#message", message));

            if(!response.equals("ok")) {
                log.error("Slack error : " + response);
            }
        } catch (Exception e) {
            log.error ("exception msg", e);
        }
    }
}

slack은  webhook이라는 기능을 사용했는데, slack에서 특정 URL을 발급받아 사용하면 된다.

 

 webhooks에 대해 살펴보자.

 

여기서 난감한 상황은 어쩄든 slack을 발송하려면 통신이 필요한데 장비 혹은 소프트웨어의 특정 문제 때문에 계속 통신이 실패한다면 이것을 나한테 어떻게 알려줄까?(ex. 너 지금 아무 통신을 할 수 없어!) 다른 소프트웨어 툴을 사용하지 않고도 할 수 있는 방법이 있을까..?

반응형
Comments