Files
KissMe/KissMeIndex/Sources/KissIndex+0002.swift
2023-06-26 18:23:45 +09:00

168 lines
5.6 KiB
Swift

//
// KissIndex+0002.swift
// KissMeIndex
//
// Created by ened-book-m1 on 2023/06/20.
//
import Foundation
import KissMe
private struct KMI_0002_Config: Codable {
enum Strategy: String, Codable {
case balanceRatioIncreased = "BALANCE_RATIO_INCREASED"
case shorts3DayIncreased = "3DAY_INCREASED"
}
let strategy: Strategy
static let `default`: Strategy = .balanceRatioIncreased
}
extension KissIndex {
func indexSet_0002(date: Date, config: String?, kmi: KissIndexType) {
if productsCount == 0 {
loadShop(url: KissIndex.shopProductsUrl)
}
let strategy = loadConfig(config)
let semaphore = DispatchSemaphore(value: 0)
Task {
do {
switch strategy {
case .balanceRatioIncreased:
try await balanceRatioIncreased(date: date, kmi: kmi)
case .shorts3DayIncreased:
try await shorts3DayIncreased(date: date, kmi: kmi)
}
} catch {
writeError(error, kmi: kmi)
}
semaphore.signal()
}
semaphore.wait()
}
private func loadConfig(_ config: String?) -> KMI_0002_Config.Strategy {
var strategy = KMI_0002_Config.default
if let config = config {
do {
let configUrl = URL.currentDirectory().appending(path: config)
let data = try Data(contentsOf: configUrl, options: .uncached)
let configData = try JSONDecoder().decode(KMI_0002_Config.self, from: data)
strategy = configData.strategy
} catch {
}
}
return strategy
}
/// 3 (0.01%) .
///
private func balanceRatioIncreased(date: Date, kmi: KissIndexType) async throws {
let increasedRatioLock = NSLock()
var increasedRatio = [String: Double]()
let _ = try await collectShorts(date: date, recentCount: 3) { productNo, shorts in
if shorts.count >= 3, let endShort = shorts.first, let startShort = shorts.last {
if let endRatio = Double(endShort.shortSellingBalanceRatio),
let startRatio = Double(startShort.shortSellingBalanceRatio) {
let increaseRatio = endRatio - startRatio
if abs(increaseRatio) > 0.01 {
increasedRatioLock.lock()
if let _ = increasedRatio[productNo] {
increasedRatio[productNo]! += increaseRatio
}
else {
increasedRatio[productNo] = increaseRatio
}
increasedRatioLock.unlock()
return true
}
}
}
return false
}
var scoreMap = [String: Double]()
for (productNo, ratio) in increasedRatio {
let score = -ratio
if let _ = scoreMap[productNo] {
scoreMap[productNo]! += score
}
else {
scoreMap[productNo] = score
}
}
normalizeAndWrite(scoreMap: scoreMap, includeName: true, kmi: kmi)
}
/// 3 (0.01%) .
///
private func shorts3DayIncreased(date: Date, kmi: KissIndexType) async throws {
let sumRatioLock = NSLock()
var sumRatio = [String: Double]()
let prices = try await collectPrices(date: date, recentCount: 3) { prices in
if prices.count >= 3 {
var curDay: String? = nil
var aPriceEachDay = [CapturePrice]()
for price in prices {
if curDay != price.stockBusinessDate {
aPriceEachDay.append(price)
curDay = price.stockBusinessDate
}
}
/// lastShortSellingConclusionQuantity .
let sumConclusionQuantity = aPriceEachDay.reduce(0, { $0 + (Int($1.lastShortSellingConclusionQuantity) ?? 0) })
let ratio = Double(sumConclusionQuantity * 100) / Double(prices[0].listedStockCount)!
//print("ratio: \(ratio), sumConclusionQuantity: \(sumConclusionQuantity)")
guard ratio > 0.01 else {
return false
}
let productNo = prices[0].shortProductCode
sumRatioLock.lock()
if let _ = sumRatio[productNo] {
sumRatio[productNo]! += ratio
}
else {
sumRatio[productNo] = ratio
}
sumRatioLock.unlock()
return true
}
return false
}
var scoreMap = [String: Double]()
for price in prices {
let productNo = price.shortProductCode
let score = -(sumRatio[productNo] ?? 0)
if let _ = scoreMap[productNo] {
scoreMap[productNo]! += score
}
else {
scoreMap[productNo] = score
}
}
normalizeAndWrite(scoreMap: scoreMap, includeName: true, kmi: kmi)
}
}