Add Ticker24h support: hourly market snapshots with USD-normalized volume filtering
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
import { ref } from 'vue'
|
||||
import DetailsEditDialog from './DetailsEditDialog.vue'
|
||||
import ResearchViewDialog from './ResearchViewDialog.vue'
|
||||
import { useIndicatorStore } from '../stores/indicators'
|
||||
import { useIndicatorTypesStore } from '../stores/indicatorTypes'
|
||||
|
||||
const props = defineProps<{
|
||||
category: 'indicator' | 'strategy' | 'research'
|
||||
@@ -14,6 +16,9 @@ const editingName = ref('')
|
||||
const viewDialogVisible = ref(false)
|
||||
const viewingName = ref('')
|
||||
|
||||
const indicatorStore = useIndicatorStore()
|
||||
const indicatorTypesStore = useIndicatorTypesStore()
|
||||
|
||||
function openEdit(name: string) {
|
||||
editingName.value = name
|
||||
dialogVisible.value = true
|
||||
@@ -24,8 +29,28 @@ function openView(name: string) {
|
||||
viewDialogVisible.value = true
|
||||
}
|
||||
|
||||
function addToChart(pandasTaName: string, displayName: string) {
|
||||
const type = indicatorTypesStore.types[pandasTaName]
|
||||
if (!type) return
|
||||
const defaultParams: Record<string, any> = {}
|
||||
for (const [k, p] of Object.entries(type.metadata.parameters)) {
|
||||
defaultParams[k] = p.default
|
||||
}
|
||||
const now = Math.floor(Date.now() / 1000)
|
||||
indicatorStore.addIndicator({
|
||||
id: `${pandasTaName}_${Date.now()}`,
|
||||
pandas_ta_name: pandasTaName,
|
||||
instance_name: displayName,
|
||||
parameters: defaultParams,
|
||||
visible: true,
|
||||
pane: type.metadata.pane,
|
||||
custom_metadata: type.metadata,
|
||||
created_at: now,
|
||||
modified_at: now,
|
||||
})
|
||||
}
|
||||
|
||||
function onUpdated(_payload: { category: string; name: string; success: boolean; error?: string }) {
|
||||
// Hook for handling the details_updated response — add logic here as needed
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -35,8 +60,9 @@ function onUpdated(_payload: { category: string; name: string; success: boolean;
|
||||
<div v-for="row in rows" :key="row.id" class="item-row">
|
||||
<span class="item-name">{{ row.display_name }}</span>
|
||||
<span class="item-desc">{{ row.description ?? '' }}</span>
|
||||
<button v-if="category === 'research'" class="view-btn" @click="openView(row.display_name)">View</button>
|
||||
<button class="edit-btn" @click="openEdit(row.display_name)">Edit</button>
|
||||
<button class="edit-btn" @click="openEdit(row.display_name)">Spec</button>
|
||||
<button v-if="category === 'research'" class="view-btn" @click="openView(row.display_name)">Result</button>
|
||||
<button v-if="category === 'indicator'" class="use-btn" @click="addToChart(row.id, row.display_name)">Use</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -138,4 +164,21 @@ function onUpdated(_payload: { category: string; name: string; success: boolean;
|
||||
border-color: #089981;
|
||||
color: #089981;
|
||||
}
|
||||
|
||||
.use-btn {
|
||||
flex-shrink: 0;
|
||||
background: none;
|
||||
border: 1px solid #3d3d3d;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.use-btn:hover {
|
||||
border-color: #4a9eca;
|
||||
color: #4a9eca;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, computed, onUnmounted } from 'vue'
|
||||
import { ref, watch, computed, onUnmounted, nextTick } from 'vue'
|
||||
import Dialog from 'primevue/dialog'
|
||||
import Button from 'primevue/button'
|
||||
import { useEditor, EditorContent } from '@tiptap/vue-3'
|
||||
@@ -54,12 +54,13 @@ watch(() => props.visible, (v) => {
|
||||
}
|
||||
})
|
||||
|
||||
const messageHandler = (msg: WebSocketMessage) => {
|
||||
const messageHandler = async (msg: WebSocketMessage) => {
|
||||
if (msg.category !== props.category || msg.name !== props.name) return
|
||||
|
||||
if (msg.type === 'details_data') {
|
||||
originalContent.value = msg.details ?? ''
|
||||
editor.value?.commands.setContent(msg.details ?? '')
|
||||
await nextTick()
|
||||
originalContent.value = (editor.value?.storage as any).markdown.getMarkdown() ?? ''
|
||||
loadState.value = 'ready'
|
||||
} else if (msg.type === 'details_error') {
|
||||
loadError.value = msg.error ?? 'Failed to load details'
|
||||
|
||||
Reference in New Issue
Block a user